예제 #1
0
 internal VirtualTreeExtendedHitInfo(ref VirtualTreeHitInfo hitInfo, ref ExtraHitInfo extraHitInfo)
 {
     myHitInfo      = hitInfo;
     myExtraHitInfo = extraHitInfo;
 }
        private VirtualTreeHitInfo HitInfo(int x, int y, out ExtraHitInfo extraInfo, bool populateExtras)
        {
            extraInfo = new ExtraHitInfo();
            var target = VirtualTreeHitTargets.Uninitialized;
            var absIndex = VirtualTreeConstant.NullIndex;
            var column = 0;
            var nativeColumn = 0;
            var rawRow = absIndex;
            var rawColumn = absIndex;

            if (x < 0)
            {
                target |= VirtualTreeHitTargets.ToLeft;
            }
            else if (x > ClientSize.Width)
            {
                target |= VirtualTreeHitTargets.ToRight;
            }

            if (y < 0)
            {
                target |= VirtualTreeHitTargets.Above;
            }
            else if (y > ClientSize.Height)
            {
                target |= VirtualTreeHitTargets.Below;
            }
            if (target != VirtualTreeHitTargets.Uninitialized)
            {
                return new VirtualTreeHitInfo(absIndex, column, target);
            }

            absIndex = rawRow = IndexFromPoint(x, y);

            if ((absIndex < 0)
                ||
                (myTree == null)
                ||
                (absIndex >= myTree.VisibleItemCount))
            {
                return new VirtualTreeHitInfo(VirtualTreeConstant.NullIndex, column, VirtualTreeHitTargets.NoWhere);
            }

            // Shift by the horizontal scroll position
            var scrollShift = myXPos;
            x += scrollShift;

            // Determine the current column
            int level;
            int relIndex;
            IBranch branch;
            var multiColumn = myMctree != null;
            var labelShift = 0;
            int itemWidth;
            int itemLeft;
            if (multiColumn)
            {
                column = rawColumn = ColumnHitTest(x, out itemLeft, out itemWidth);
                int columns;
                if (myColumnPermutation == null)
                {
                    columns = myMctree.ColumnCount;
                    nativeColumn = column;
                }
                else
                {
                    columns = myColumnPermutation.VisibleColumnCount;
                    nativeColumn = myColumnPermutation.GetNativeColumn(column);
                }
                if (column >= columns)
                {
                    return new VirtualTreeHitInfo(VirtualTreeConstant.NullIndex, column, VirtualTreeHitTargets.NoWhere);
                }
            }
            else
            {
                itemLeft = 0;
                itemWidth = ClientSize.Width;
            }
            var leadingBlanksLeft = itemLeft;
            var checkRootLines = GetAnyStyleFlag(VTCStyleFlags.HasRootLines | VTCStyleFlags.HasRootButtons);
            var info = myTree.GetItemInfo(absIndex, nativeColumn, checkRootLines && nativeColumn > 0);
            VirtualTreeHitTargets blankTargetBit = 0;
            var testingBlank = info.Blank;
            if (multiColumn)
            {
                var expansion = myTree.GetBlankExpansion(absIndex, column, myColumnPermutation);
                //Debug.WriteLine(string.Format("Left/Top ({0}, {1}) Anchor ({2}, {3}) Width {4} Height {5}", expansion.LeftColumn, expansion.TopRow, expansion.AnchorColumn, expansion.TopRow, expansion.Width, expansion.Height));
                if (expansion.AnchorColumn != VirtualTreeConstant.NullIndex)
                {
                    if (testingBlank)
                    {
                        blankTargetBit = VirtualTreeHitTargets.OnBlankItem;
                        absIndex = expansion.TopRow;
                        column = expansion.AnchorColumn;
                        nativeColumn = (myColumnPermutation == null) ? column : myColumnPermutation.GetNativeColumn(column);
                        // If the expansion width is 1, then we're in a blank expansion below
                        // the last item in a column. Treat/ this the same as hovering on the
                        // main item, except that we don't acknowledge glyph or button hovers.
                        info = myTree.GetItemInfo(absIndex, nativeColumn, checkRootLines && nativeColumn > 0);
                    }
                    if (expansion.Width > 1)
                    {
                        // The item is wider than a single column. This type of item
                        // always extends the full width of the tree. Retrieve new information.
                        GetColumnBounds(expansion.LeftColumn, expansion.RightColumn, out itemLeft, out itemWidth);
                        leadingBlanksLeft = itemLeft;
                        if (expansion.LeftColumn != expansion.AnchorColumn)
                        {
                            GetColumnBounds(expansion.AnchorColumn, expansion.RightColumn, out itemLeft, out itemWidth);
                        }
                    }
                }
            }
            if (info.Blank)
            {
                return new VirtualTreeHitInfo(rawRow, rawColumn, VirtualTreeHitTargets.OnBlankItem);
            }
            else if (itemLeft != leadingBlanksLeft
                     && x < itemLeft)
            {
                return new VirtualTreeHitInfo(
                    absIndex, column, nativeColumn, rawRow, rawColumn, VirtualTreeHitTargets.OnItemLeft | blankTargetBit);
            }

            level = info.Level;
            branch = info.Branch;
            relIndex = info.Row;

            // Shift by the indent width
            var xItemStart = level * myIndentWidth + itemLeft;
            if (checkRootLines && (nativeColumn == 0 || !info.SimpleCell))
            {
                xItemStart += myIndentWidth;
            }

            if (x < xItemStart)
            {
                // We're in the indent region
                target = VirtualTreeHitTargets.OnItemIndent;

                // See if we're actually on a button, not just an indent
                if (HasButtons && ((x + myIndentWidth) > xItemStart))
                {
                    if (myTree.IsExpandable(absIndex, nativeColumn))
                    {
                        target = VirtualTreeHitTargets.OnItemButton;
                    }
                }
                //UNDONE Find the item whose expansion we're clicking on, and check whether
                //or not we're within the bounds of the button width of the item.
                return new VirtualTreeHitInfo(absIndex, column, nativeColumn, rawRow, rawColumn, target | blankTargetBit);
            }
            else
            {
                x -= xItemStart;
                var tddMasks = new VirtualTreeDisplayDataMasks(
                    VirtualTreeDisplayMasks.State, VirtualTreeDisplayStates.Bold | VirtualTreeDisplayStates.TextAlignFar);
                if (myImageWidth > 0)
                {
                    tddMasks.Mask |= VirtualTreeDisplayMasks.Image;
                }
                if (myStateImageWidth > 0)
                {
                    tddMasks.Mask |= VirtualTreeDisplayMasks.StateImage;
                }
                var tdd = branch.GetDisplayData(relIndex, info.Column, tddMasks);

                // Check if we're on the state icon.
                if (myStateImageWidth > 0)
                {
                    if (tdd.StateImageIndex >= 0)
                    {
                        if (x < myStateImageWidth)
                        {
                            target = VirtualTreeHitTargets.OnItemStateIcon;

                            if (StandardCheckBoxes
                                && tdd.StateImageList == null
                                &&
                                (tdd.StateImageIndex == (int)StandardCheckBoxImage.Unchecked
                                 || tdd.StateImageIndex == (int)StandardCheckBoxImage.Checked
                                 || tdd.StateImageIndex == (int)StandardCheckBoxImage.Indeterminate))
                            {
                                target |= VirtualTreeHitTargets.StateIconHotTracked;
                            }
                        }
                        else
                        {
                            x -= myStateImageWidth;
                        }
                        labelShift += myStateImageWidth;
                    }
                }

                // Check if we're on the image icon
                if (myImageWidth > 0)
                {
                    if (tdd.Image != -1)
                    {
                        if (x < myImageWidth)
                        {
                            if (target == VirtualTreeHitTargets.Uninitialized)
                            {
                                target = VirtualTreeHitTargets.OnItemIcon;
                            }
                        }
                        else
                        {
                            x -= myImageWidth;
                        }
                        labelShift += myImageWidth;
                    }
                }

                if (populateExtras || target == VirtualTreeHitTargets.Uninitialized)
                {
                    // See where we are on the item's label
                    var labelFont = (0 == (tdd.State & VirtualTreeDisplayStates.Bold)) ? Font : BoldFont;
                    var iWidth = ListItemStringWidth(labelFont, ref info);
                    var textAlign = GetLabelTextAlignment(ref tdd);
                    if (RightToLeft == RightToLeft.Yes)
                    {
                        // For purposes of hit test calculations, RTL switches near/far alignment. 
                        textAlign = textAlign == StringAlignment.Far ? StringAlignment.Near : StringAlignment.Far;
                    }
                    if (target == VirtualTreeHitTargets.Uninitialized)
                    {
                        if (textAlign == StringAlignment.Near)
                        {
                            target = (x < iWidth)
                                         ? VirtualTreeHitTargets.OnItemLabel
                                         : VirtualTreeHitTargets.OnItemRight;
                        }
                        else
                        {
                            // add labelShift and xItemStart because they've been subtracted from original x value above.
                            target = (x + labelShift + xItemStart > itemLeft + itemWidth - iWidth)
                                         ? VirtualTreeHitTargets.OnItemLabel
                                         : VirtualTreeHitTargets.OnItemLeft;
                        }
                    }

                    if (populateExtras)
                    {
                        var currentTopIndex = TopIndex;
                        extraInfo.IsTruncated =
                            (rawRow != absIndex && absIndex < currentTopIndex) ||
                            ((rawRow == absIndex) &&
                             (0 == (target & (VirtualTreeHitTargets.OnItemRight | VirtualTreeHitTargets.OnItemLeft))) &&
                             ((xItemStart + labelShift + SystemInformation.Border3DSize.Width + iWidth > itemLeft + itemWidth) ||
                              (labelShift + SystemInformation.Border3DSize.Width < 0)));
                        extraInfo.LabelOffset = labelShift;
                        var top = (rawRow - currentTopIndex) * myItemHeight;
                        extraInfo.ClippedItemRectangle = new Rectangle(
                            xItemStart - scrollShift,
                            top,
                            (extraInfo.IsTruncated || textAlign == StringAlignment.Far)
                                ? itemLeft + itemWidth - xItemStart
                                : labelShift + iWidth,
                            // in right align case, clipped item rectangle will always extend the full width, since text draws from the right.
                            myItemHeight);
                        extraInfo.FullLabelRectangle = new Rectangle(
                            xItemStart + labelShift - scrollShift,
                            top,
                            iWidth,
                            myItemHeight);
                        if (textAlign == StringAlignment.Far)
                        {
                            // account for alignment away from glyph.
                            extraInfo.FullLabelRectangle.X = itemLeft + itemWidth - scrollShift - iWidth;
                        }
                        else if (multiColumn
                                 && HasVerticalGridLines
                                 && (column != 0))
                        {
                            // account for vertical gridlines
                            extraInfo.FullLabelRectangle.X += 1;
                        }
                        extraInfo.LabelFont = labelFont;
                        extraInfo.LabelFormat = StringFormat;
                        extraInfo.LabelFormat.Alignment = GetLabelTextAlignment(ref tdd);
                            // get alignment again, so it's not adjusted for RTL.
                    }
                }
            }
            Debug.Assert(target != VirtualTreeHitTargets.Uninitialized);
            return new VirtualTreeHitInfo(absIndex, column, nativeColumn, rawRow, rawColumn, target | blankTargetBit);

            /*INDEX index;
            int cxState, cxImage;
            int xShift;
            ULONG Level;
            IVsLiteTreeList *ptl;
            ULONG ListIndex;
            WORD iWidth;
            VSTREEDISPLAYDATA tdd;

            xShift = Level * pTree->cxIndent;
            xShift -= pTree->xPos;

            if ((pTree->ci.style & (TVS_HASLINES | TVS_HASBUTTONS)) &&
                (pTree->ci.style &TVS_LINESATROOT))
            {
                // Subtract some more to make up for the pluses at the root
                xShift += pTree->cxIndent;
            }

            x -= xShift;

            //Get image offsets.  Not all items have an image, so
            //we have to check that as well here.
            cxState = 0;
            cxImage = pTree->cxImage;
            tdd.Mask = 0;
            tdd.StateMask = 0;
            if (cxImage) 
            {
                tdd.Mask |= TDM_IMAGE;
                tdd.hImageList = NULL;
            }
            if (pTree->himlState) 
            {
                tdd.Mask |= TDM_STATE;
                tdd.StateMask |= TDS_STATEIMAGEMASK;
                tdd.State = 0; //in case of failure
            }
            if (tdd.Mask) 
            {
                ptl->GetDisplayData(ListIndex, &tdd);
                cxState = TV_StateIndex(tdd.State) ? pTree->cxState : 0;
                if (cxImage && tdd.hImageList == NULL && tdd.Image == (USHORT)(-1)) 
                {
                    cxImage = 0;
                }
            }

            //iWidth adjusted from regular
            //treeview which caches iWidth for an item.
            iWidth = TV_ListItemStringWidth(pTree, ptl, ListIndex);
            if (x <= (int) (cxImage + cxState)) 
            {
                if (x >= 0) 
                {
                    if (pTree->himlState &&  (x < cxState)) 
                    {
                        *wHitCode = TVHT_ONITEMSTATEICON;
                    } 
                    else if (pTree->hImageList && (x < (int) cxImage + cxState)) 
                    {
                        *wHitCode = TVHT_ONITEMICON;
                    } 
                    else 
                    {
                        *wHitCode = TVHT_ONITEMLABEL;
                    }
                } 
                else 
                {
                    if ((x >= -pTree->cxIndent) && (pTree->ci.style & TVS_HASBUTTONS)) 
                    {
                        BOOL expandable = FALSE;
                        pTree->pVsTree->GetExpandableAbsolute(index, &expandable);
                        *wHitCode = expandable ? TVHT_ONITEMBUTTON : TVHT_ONITEMINDENT;
                    }
                    else 
                    {
                        *wHitCode = TVHT_ONITEMINDENT;
                    }
                }
                if (pfIsStringTruncated) 
                {
                    *pfIsStringTruncated = ((xShift + cxImage + cxState + g_cxEdge + iWidth > pTree->cxWnd) ||
                        (xShift + cxImage + cxState + g_cxEdge < 0));
                }
            }
            else 
            {
                if (x <= (int) (iWidth + cxImage + cxState)) 
                {
                    *wHitCode = TVHT_ONITEMLABEL;
                    if (pfIsStringTruncated) 
                    {
                        *pfIsStringTruncated = ((xShift + cxImage + cxState + g_cxEdge + iWidth > pTree->cxWnd) ||
                            (xShift + cxImage + cxState + g_cxEdge < 0));
                    } 
                }
                else 
                {
                    *wHitCode = TVHT_ONITEMRIGHT;
                    if (pfIsStringTruncated) 
                    {
                        *pfIsStringTruncated = false;
                    } 
                }
            }

            if (lprcItem && (*wHitCode & TVHT_ONITEM)) 
            {
                lprcItem->left = xShift;
                lprcItem->right = (pfIsStringTruncated && *pfIsStringTruncated) ? pTree->cxWnd : xShift + cxImage + cxState + iWidth;
                lprcItem->top = (index - pTree->iTop) * pTree->cyItem;
                lprcItem->bottom = lprcItem->top + pTree->cyItem;
                if (pcxShiftToLabel) 
                {
                    *pcxShiftToLabel = (LONG)(cxState + cxImage);
                }
            }

            if (ptl) 
            {
                ptl->Release();
            }
            if (pLevel) 
            {
                *pLevel = Level;
            }
            return (INDEX) index;*/
        }
            public void Activate(ref VirtualTreeHitInfo hit, ref ExtraHitInfo extraInfo, ref Point mousePos, bool immediateActivation)
            {
                var hWnd = Handle.ToInt32();
                if (hWnd == 0)
                {
                    return;
                }

                var ctrlhWnd = Handle;
                NativeMethods.SendMessage(ctrlhWnd, NativeMethods.TTM_ACTIVATE, 0, hWnd);
                if (hit.Row != VirtualTreeConstant.NullIndex)
                {
                    var ti = new NativeMethods.TOOLINFO();
                    ti.SetSize();
                    ti.uId = hWnd;
                    ti.uFlags = NativeMethods.TTF_IDISHWND;
                    ti.rect = NativeMethods.RECT.FromXYWH(
                        extraInfo.ClippedItemRectangle.X,
                        extraInfo.ClippedItemRectangle.Y,
                        extraInfo.ClippedItemRectangle.Width,
                        extraInfo.ClippedItemRectangle.Height);
                    NativeMethods.SendMessage(
                        ctrlhWnd, NativeMethods.TTM_SETDELAYTIME, NativeMethods.TTDT_INITIAL, immediateActivation ? 0 : 250);
                    NativeMethods.SendMessage(ctrlhWnd, NativeMethods.TTM_NEWTOOLRECT, 0, ref ti);
                    NativeMethods.SendMessage(ctrlhWnd, NativeMethods.TTM_ACTIVATE, 1, hWnd);
                    Font = extraInfo.LabelFont;
                    myFormat = extraInfo.LabelFormat;
                    myFullLabelRectangle = extraInfo.FullLabelRectangle;
                    myActivatingMousePos = mousePos;
                }
            }
예제 #4
0
 internal VirtualTreeExtendedHitInfo(ref VirtualTreeHitInfo hitInfo, ref ExtraHitInfo extraHitInfo)
 {
     myHitInfo = hitInfo;
     myExtraHitInfo = extraHitInfo;
 }