private KTreeNodeMeasurements(KTreeNodeMeasurements orig, int x, int y) { this._node = orig._node; this._options = orig._options; this._paddingOveral = orig._paddingOveral; this._sizes = (Size[])orig._sizes.Clone(); // The node rectangle is the sum of the widths, and the maximum height (plus padding). // TODO: special handling for control part, make that fit with e.g. a Dock option? _nodeRect = new Rectangle(orig._nodeRect.X + x, y + orig._nodeRect.Y, _sizes.Select((i) => i.Width).Sum() + _paddingOveral.Horizontal, _sizes.Select((i) => i.Height).Max() + _paddingOveral.Vertical); for (int i = 0; i < (int)Part.None; ++i) { _paddingInternal[i] = new Padding(); // Align any parts whose height does not match the total height if (_sizes[i].Height != InnerRect.Height) { _paddingInternal[i].Bottom = (InnerRect.Height - _sizes[i].Height) / 2; _paddingInternal[i].Top = (InnerRect.Height - _sizes[i].Height) - _paddingInternal[i].Bottom; // Quick hack to make sure checkboxes are properly aligned, make the rect square again // TODO: use padding/dock modes for this if (i == (int)Part.CheckBox && !_sizes[i].IsEmpty && _sizes[i].IsSquare()) { _paddingInternal[i].Left = _paddingInternal[i].Bottom; _paddingInternal[i].Right = _paddingInternal[i].Top; } } } }
protected KTreeNodeMeasurements GetNodeSize(Graphics graphics, KTreeNode node) { KTreeNodeMeasurements dimension = new KTreeNodeMeasurements(node, _tree); // Expander dimension[KTreeNodeMeasurements.Part.Expander] = GetExpanderSize(graphics, node); // Checkbox if (node.Owner.CheckManager != null && node.HasCheckBox) { dimension[KTreeNodeMeasurements.Part.CheckBox] = CheckBoxRenderer.GetGlyphSize(graphics, CheckBoxState.CheckedNormal); } // Image if (_tree.Images != null) { // Image size specified by imagelist // Scale depending on resolution dimension[KTreeNodeMeasurements.Part.Image] = _tree.Images.ImageSize.ScaleDpi(graphics); } // Text size dimension[KTreeNodeMeasurements.Part.Text] = TextRenderer.MeasureText(graphics, node.Text, _tree.Font, Size.Empty, TEXT_FLAGS); // Control if (node.Control != null) { dimension[KTreeNodeMeasurements.Part.Control] = node.Control.PreferredSize; } return(dimension); }
/// <summary> /// /// </summary> /// <param name="graphics">The graphics to render into</param> /// <param name="node">The node</param> /// <param name="scrollOffset">The current scrollbar offset</param> /// <param name="highlight">If not null, the part of the node that is highlighted. May be Part.None to indicate the row is /// highlighted, but not a specific part</param> public void RenderNode(Graphics graphics, KTreeNode node, Point scrollOffset, KTreeNodeMeasurements.Part?highlight) { // Make sure the node has been measured if (node.EffectiveDimension == null) { MeasureNode(graphics, node); } KTreeNodeMeasurements dims = node.EffectiveDimension.Offset(-scrollOffset.X, -scrollOffset.Y); Rectangle containerRect = dims.NodeRect; containerRect.X = _clientRect.X; containerRect.Width = Math.Max(_totalRect.Width, _clientRect.Width); // Overlap the rectangle with the control border, to prevent duplicate lines containerRect = containerRect.Expand(new Padding(_tree.BorderThickness)); // Selection background RenderNodeOutline(graphics, node, _tree.FullRowSelect ? containerRect : dims.NodeRect, highlight); // Expander if (node.ChildLoader.NeedsExpander) { RenderNodeExpander(graphics, node, dims.GetPartRect(KTreeNodeMeasurements.Part.Expander, true), highlight); } // Checkbox if (_tree.CheckManager != null && node.HasCheckBox) { RenderCheckBox(graphics, node, dims.GetPartRect(KTreeNodeMeasurements.Part.CheckBox, true), highlight); } // Images if (_tree.Images != null && node.ImageIndex.HasValue && node.ImageIndex >= 0 && node.ImageIndex < _tree.Images.Images.Count) { Rectangle imageRect = dims.GetPartRect(KTreeNodeMeasurements.Part.Image, true); // TODO: if the rectangle is larger than the image, this probably leads to upscaling. // if the imagelist stores high-res icons as 16x16, that throws away resolution. // make a custom image list to handle this? That could also handle scaling automatically Image image = _tree.Images.Images[node.ImageIndex.Value]; graphics.DrawImage(image, imageRect.X, imageRect.Y, imageRect.Width, imageRect.Height); } // Text RenderNodeText(graphics, node, dims.GetPartRect(KTreeNodeMeasurements.Part.Text, true), highlight); // Control if (node.Control != null) { node.Control.Bounds = dims.GetPartRect(KTreeNodeMeasurements.Part.Control, true); } }
internal KTreeNodeMeasurements MeasureNode(Graphics graphics, KTreeNode node) { // Determine the row rectangle KTreeNodeMeasurements dims = GetNodeSize(graphics, node).Offset(_totalRect.X, _totalRect.Height); node.EffectiveDimension = dims; // Set up for the next node _totalRect.Height += dims.NodeRect.Height; _totalRect.Width = Math.Max(_totalRect.Right, dims.NodeRect.Right) - _totalRect.X; return(dims); }