public override void ArcTo(double x, double y, double size, Corner corner) { float left = (float)(Math.Min(x, _lastPoint.X) - (corner == Corner.TopRight || corner == Corner.BottomRight ? size : 0)); float top = (float)(Math.Min(y, _lastPoint.Y) - (corner == Corner.BottomLeft || corner == Corner.BottomRight ? size : 0)); _graphicsPath.AddArc(left, top, (float)size * 2, (float)size * 2, GetStartAngle(corner), 90); _lastPoint = new RPoint(x, y); }
/// <summary> /// Convert from WinForms point to core point. /// </summary> public static PointF[] Convert(RPoint[] points) { PointF[] myPoints = new PointF[points.Length]; for (int i = 0; i < points.Length; i++) myPoints[i] = Convert(points[i]); return myPoints; }
/// <summary> /// Initializes a new instance of the <see cref="RRect" /> class with the specified location and size. /// </summary> /// <param name="location">A <see cref="RPoint" /> that represents the upper-left corner of the rectangular region.</param> /// <param name="size">A <see cref="RSize" /> that represents the width and height of the rectangular region.</param> public RRect(RPoint location, RSize size) { _x = location.X; _y = location.Y; _width = size.Width; _height = size.Height; }
/// <summary> /// Translates a given <see cref="RPoint" /> by a specified /// <see /// cref="T:System.Drawing.SizeF" /> /// . /// </summary> /// <returns> /// The translated <see cref="RPoint" />. /// </returns> /// <param name="pt"> /// The <see cref="RPoint" /> to translate. /// </param> /// <param name="sz"> /// The <see cref="T:System.Drawing.SizeF" /> that specifies the numbers to add to the coordinates of /// <paramref /// name="pt" /> /// . /// </param> public static RPoint Add(RPoint pt, RSize sz) { return new RPoint(pt.X + sz.Width, pt.Y + sz.Height); }
/// <summary> /// Translates a given <see cref="RPoint" /> by a specified /// <see /// cref="T:System.Drawing.SizeF" /> /// . /// </summary> /// <returns> /// The translated <see cref="RPoint" />. /// </returns> /// <param name="pt"> /// The <see cref="RPoint" /> to translate. /// </param> /// <param name="sz"> /// The <see cref="T:System.Drawing.SizeF" /> that specifies the numbers to add to the coordinates of /// <paramref /// name="pt" /> /// . /// </param> public static RPoint Add(RPoint pt, RSize sz) { return(new RPoint(pt.X + sz.Width, pt.Y + sz.Height)); }
/// <summary> /// Initializes a new instance of the <see cref="RSize" /> structure from the specified <see cref="RPoint" /> structure. /// </summary> /// <param name="pt">The <see cref="RPoint" /> structure from which to initialize this <see cref="RSize" /> structure.</param> public RSize(RPoint pt) { _width = pt.X; _height = pt.Y; }
/// <summary> /// Draw the given string using the given font and foreground color at given location. /// </summary> /// <param name="str">the string to draw</param> /// <param name="font">the font to use to draw the string</param> /// <param name="color">the text color to set</param> /// <param name="point">the location to start string draw (top-left)</param> /// <param name="size">used to know the size of the rendered text for transparent text support</param> /// <param name="rtl">is to render the string right-to-left (true - RTL, false - LTR)</param> public abstract void DrawString(String str, RFont font, RColor color, RPoint point, RSize size, bool rtl);
/// <summary> /// Init. /// </summary> /// <param name="location">the location to scroll to</param> public HtmlScrollEventArgs(RPoint location) { _location = location; }
/// <summary> /// Adjusts the location of this rectangle by the specified amount. /// </summary> /// <param name="pos">The amount to offset the location. </param> public void Offset(RPoint pos) { Offset(pos.X, pos.Y); }
/// <summary> /// Deeply offsets the top of the box and its contents /// </summary> /// <param name="amount"></param> internal void OffsetTop(double amount) { List<CssLineBox> lines = new List<CssLineBox>(); foreach (CssLineBox line in Rectangles.Keys) lines.Add(line); foreach (CssLineBox line in lines) { RRect r = Rectangles[line]; Rectangles[line] = new RRect(r.X, r.Y + amount, r.Width, r.Height); } foreach (CssRect word in Words) { word.Top += amount; } foreach (CssBox b in Boxes) { b.OffsetTop(amount); } if (_listItemBox != null) _listItemBox.OffsetTop(amount); Location = new RPoint(Location.X, Location.Y + amount); }
/// <summary> /// Handle mouse down to handle selection. /// </summary> /// <param name="parent">the control hosting the html to invalidate</param> /// <param name="loc">the location of the mouse on the html</param> /// <param name="isMouseInContainer"> </param> public void HandleMouseDown(RControl parent, RPoint loc, bool isMouseInContainer) { bool clear = !isMouseInContainer; if (isMouseInContainer) { _mouseDownInControl = true; _isDoubleClickSelect = (DateTime.Now - _lastMouseDown).TotalMilliseconds < 400; _lastMouseDown = DateTime.Now; _mouseDownOnSelectedWord = false; if (_root.HtmlContainer.IsSelectionEnabled && parent.LeftMouseButton) { var word = DomUtils.GetCssBoxWord(_root, loc); if (word != null && word.Selected) { _mouseDownOnSelectedWord = true; } else { clear = true; } } else if (parent.RightMouseButton) { var rect = DomUtils.GetCssBoxWord(_root, loc); var link = DomUtils.GetLinkBox(_root, loc); if (_root.HtmlContainer.IsContextMenuEnabled) { _contextMenuHandler.ShowContextMenu(parent, rect, link); } clear = rect == null || !rect.Selected; } } if (clear) { ClearSelection(); parent.Invalidate(); } }
public override void Show(RControl parent, RPoint location) { _contextMenu.Show(((ControlAdapter)parent).Control, Utils.ConvertRound(location)); }
/// <summary> /// returns the box with the attribute "clickable" that has been clicked /// </summary> /// <param name="box"></param> /// <param name="location"></param> /// <returns></returns> public static CssBox SearchClickedBox(CssBox box, RPoint location) { if (box != null) { if (box.GetAttribute("clickable") != "" && box.ClientRectangle.Contains(location)) return box; if (box.ClientRectangle.IsEmpty || box.ClientRectangle.Contains(location)) { foreach (var childBox in box.Boxes) { var foundBox = SearchClickedBox(childBox, location); if (foundBox != null) return foundBox; } } } return null; }
/// <summary> /// Check if the given location is inside the given box deep.<br/> /// Check inner boxes and all lines that the given box spans to. /// </summary> /// <param name="box">the box to check</param> /// <param name="location">the location to check</param> /// <returns>true - location inside the box, false - otherwise</returns> public static bool IsInBox(CssBox box, RPoint location) { foreach (var line in box.Rectangles) { if (line.Value.Contains(location)) return true; } foreach (var childBox in box.Boxes) { if (IsInBox(childBox, location)) return true; } return false; }
/// <summary> /// Get css link box under the given sub-tree at the given x,y location.<br/> /// the location must be in correct scroll offset. /// </summary> /// <param name="box">the box to start search from</param> /// <param name="location">the location to find the box by</param> /// <returns>css link box if exists or null</returns> public static CssBox GetLinkBox(CssBox box, RPoint location) { if (box != null) { if (box.IsClickable && box.Visibility == CssConstants.Visible) { if (IsInBox(box, location)) return box; } if (box.ClientRectangle.IsEmpty || box.ClientRectangle.Contains(location)) { foreach (var childBox in box.Boxes) { var foundBox = GetLinkBox(childBox, location); if (foundBox != null) return foundBox; } } } return null; }
/// <summary> /// Translates a <see cref="RPoint" /> by the negative of a specified size. /// </summary> /// <returns> /// The translated <see cref="RPoint" />. /// </returns> /// <param name="pt"> /// The <see cref="RPoint" /> to translate. /// </param> /// <param name="sz"> /// The <see cref="T:System.Drawing.SizeF" /> that specifies the numbers to subtract from the coordinates of /// <paramref /// name="pt" /> /// . /// </param> public static RPoint Subtract(RPoint pt, RSize sz) { return(new RPoint(pt.X - sz.Width, pt.Y - sz.Height)); }
/// <summary> /// Determines if the specified point is contained within this <see cref="RRect" /> structure. /// </summary> /// <returns> /// This method returns true if the point represented by the <paramref name="pt" /> parameter is contained within this /// <see cref="RRect" /> /// structure; otherwise false. /// </returns> /// <param name="pt">The <see cref="RPoint" /> to test.</param> public bool Contains(RPoint pt) { return(Contains(pt.X, pt.Y)); }
/// <summary> /// Paint all the words in the box. /// </summary> /// <param name="g">the device to draw into</param> /// <param name="offset">the current scroll offset to offset the words</param> private void PaintWords(RGraphics g, RPoint offset) { if (Width.Length > 0) { var isRtl = Direction == CssConstants.Rtl; foreach (var word in Words) { if (!word.IsLineBreak) { var wordPoint = new RPoint(word.Left + offset.X, word.Top + offset.Y); if (word.Selected) { // handle paint selected word background and with partial word selection var wordLine = DomUtils.GetCssLineBoxByWord(word); var left = word.SelectedStartOffset > -1 ? word.SelectedStartOffset : (wordLine.Words[0] != word && word.HasSpaceBefore ? -ActualWordSpacing : 0); var padWordRight = word.HasSpaceAfter && !wordLine.IsLastSelectedWord(word); var width = word.SelectedEndOffset > -1 ? word.SelectedEndOffset : word.Width + (padWordRight ? ActualWordSpacing : 0); var rect = new RRect(word.Left + offset.X + left, word.Top + offset.Y, width - left, wordLine.LineHeight); g.DrawRectangle(GetSelectionBackBrush(g, false), rect.X, rect.Y, rect.Width, rect.Height); if (HtmlContainer.SelectionForeColor != RColor.Empty && (word.SelectedStartOffset > 0 || word.SelectedEndIndexOffset > -1)) { g.PushClipExclude(rect); g.DrawString(word.Text, ActualFont, ActualColor, wordPoint, new RSize(word.Width, word.Height), isRtl); g.PopClip(); g.PushClip(rect); g.DrawString(word.Text, ActualFont, GetSelectionForeBrush(), wordPoint, new RSize(word.Width, word.Height), isRtl); g.PopClip(); } else { g.DrawString(word.Text, ActualFont, GetSelectionForeBrush(), wordPoint, new RSize(word.Width, word.Height), isRtl); } } else { // g.DrawRectangle(HtmlContainer.Adapter.GetPen(RColor.Black), wordPoint.X, wordPoint.Y, word.Width - 1, word.Height - 1); g.DrawString(word.Text, ActualFont, ActualColor, wordPoint, new RSize(word.Width, word.Height), isRtl); } } } } }
/// <summary> /// Handle mouse move to handle hover cursor and text selection. /// </summary> /// <param name="parent">the control hosting the html to set cursor and invalidate</param> /// <param name="loc">the location of the mouse on the html</param> public void HandleMouseMove(RControl parent, RPoint loc) { if (_root.HtmlContainer.IsSelectionEnabled && _mouseDownInControl && parent.LeftMouseButton) { if (_mouseDownOnSelectedWord) { // make sure not to start drag-drop on click but when it actually moves as it f***s mouse-up if ((DateTime.Now - _lastMouseDown).TotalMilliseconds > 200) StartDragDrop(parent); } else { HandleSelection(parent, loc, !_isDoubleClickSelect); _inSelection = _selectionStart != null && _selectionEnd != null && (_selectionStart != _selectionEnd || _selectionStartIndex != _selectionEndIndex); } } else { // Handle mouse hover over the html to change the cursor depending if hovering word, link of other. var link = DomUtils.GetLinkBox(_root, loc); if (link != null) { _cursorChanged = true; parent.SetCursorHand(); } else if (_root.HtmlContainer.IsSelectionEnabled) { var word = DomUtils.GetCssBoxWord(_root, loc); _cursorChanged = word != null && !word.IsImage && !(word.Selected && (word.SelectedStartIndex < 0 || word.Left + word.SelectedStartOffset <= loc.X) && (word.SelectedEndOffset < 0 || word.Left + word.SelectedEndOffset >= loc.X)); if (_cursorChanged) parent.SetCursorIBeam(); else parent.SetCursorDefault(); } else if (_cursorChanged) { parent.SetCursorDefault(); } } }
/// <summary> /// Determines if the specified point is contained within this <see cref="RRect" /> structure. /// </summary> /// <returns> /// This method returns true if the point represented by the <paramref name="pt" /> parameter is contained within this /// <see cref="RRect" /> /// structure; otherwise false. /// </returns> /// <param name="pt">The <see cref="RPoint" /> to test.</param> public bool Contains(RPoint pt) { return Contains(pt.X, pt.Y); }
/// <summary> /// Select the word at the given location if found. /// </summary> /// <param name="control">the control hosting the html to invalidate</param> /// <param name="loc">the location to select word at</param> public void SelectWord(RControl control, RPoint loc) { if (_root.HtmlContainer.IsSelectionEnabled) { var word = DomUtils.GetCssBoxWord(_root, loc); if (word != null) { word.Selection = this; _selectionStartPoint = loc; _selectionStart = _selectionEnd = word; control.Invalidate(); } } }
/// <summary> /// Calculate the character index and offset by characters for the given word and given offset.<br/> /// If the location is below the word line then set the selection to the end.<br/> /// If the location is to the right of the word then set the selection to the end.<br/> /// If the offset is to the left of the word set the selection to the beginning.<br/> /// Otherwise calculate the width of each substring to find the char the location is on. /// </summary> /// <param name="control">used to create graphics to measure string</param> /// <param name="word">the word to calculate its index and offset</param> /// <param name="loc">the location to calculate for</param> /// <param name="inclusive">is to include the first character in the calculation</param> /// <param name="selectionIndex">return the index of the char under the location</param> /// <param name="selectionOffset">return the offset of the char under the location</param> private static void CalculateWordCharIndexAndOffset(RControl control, CssRect word, RPoint loc, bool inclusive, out int selectionIndex, out double selectionOffset) { selectionIndex = 0; selectionOffset = 0f; var offset = loc.X - word.Left; if (word.Text == null) { // not a text word - set full selection selectionIndex = -1; selectionOffset = -1; } else if (offset > word.Width - word.OwnerBox.ActualWordSpacing || loc.Y > DomUtils.GetCssLineBoxByWord(word).LineBottom) { // mouse under the line, to the right of the word - set to the end of the word selectionIndex = word.Text.Length; selectionOffset = word.Width; } else if (offset > 0) { // calculate partial word selection int charFit; double charFitWidth; var maxWidth = offset + (inclusive ? 0 : 1.5f * word.LeftGlyphPadding); control.MeasureString(word.Text, word.OwnerBox.ActualFont, maxWidth, out charFit, out charFitWidth); selectionIndex = charFit; selectionOffset = charFitWidth; } }
/// <summary> /// Calculate the character index and offset by characters for the given word and given offset.<br/> /// <seealso cref="CalculateWordCharIndexAndOffset(RControl,CssRect,RPoint,bool)"/>. /// </summary> /// <param name="control">used to create graphics to measure string</param> /// <param name="word">the word to calculate its index and offset</param> /// <param name="loc">the location to calculate for</param> /// <param name="selectionStart">to set the starting or ending char and offset data</param> private void CalculateWordCharIndexAndOffset(RControl control, CssRect word, RPoint loc, bool selectionStart) { int selectionIndex; double selectionOffset; CalculateWordCharIndexAndOffset(control, word, loc, selectionStart, out selectionIndex, out selectionOffset); if (selectionStart) { _selectionStartIndex = selectionIndex; _selectionStartOffset = selectionOffset; } else { _selectionEndIndex = selectionIndex; _selectionEndOffset = selectionOffset; } }
/// <summary> /// Fills the interior of a polygon defined by an array of points specified by Point structures. /// </summary> /// <param name="brush">Brush that determines the characteristics of the fill. </param> /// <param name="points">Array of Point structures that represent the vertices of the polygon to fill. </param> public abstract void DrawPolygon(RBrush brush, RPoint[] points);
public override void LineTo(double x, double y) { _graphicsPath.AddLine((float)_lastPoint.X, (float)_lastPoint.Y, (float)x, (float)y); _lastPoint = new RPoint(x, y); }
/// <summary> /// Get TextureBrush object that uses the specified image and bounding rectangle. /// </summary> /// <param name="image">The Image object with which this TextureBrush object fills interiors.</param> /// <param name="dstRect">A Rectangle structure that represents the bounding rectangle for this TextureBrush object.</param> /// <param name="translateTransformLocation">The dimension by which to translate the transformation</param> public abstract RBrush GetTextureBrush(RImage image, RRect dstRect, RPoint translateTransformLocation);
/// <summary> /// Draw video image over the iframe if found. /// </summary> private void DrawImage(RGraphics g, RPoint offset, RRect rect) { if (_imageWord.Image != null) { if (rect.Width > 0 && rect.Height > 0) { if (_imageWord.ImageRectangle == RRect.Empty) g.DrawImage(_imageWord.Image, rect); else g.DrawImage(_imageWord.Image, rect, _imageWord.ImageRectangle); if (_imageWord.Selected) { g.DrawRectangle(GetSelectionBackBrush(g, true), _imageWord.Left + offset.X, _imageWord.Top + offset.Y, _imageWord.Width + 2, DomUtils.GetCssLineBoxByWord(_imageWord).LineHeight); } } } else if (_isVideo && !_imageLoadingComplete) { RenderUtils.DrawImageLoadingIcon(g, HtmlContainer, rect); if (rect.Width > 19 && rect.Height > 19) { g.DrawRectangle(g.GetPen(RColor.LightGray), rect.X, rect.Y, rect.Width, rect.Height); } } }
/// <summary> /// Check if the current selection is non empty, has some selection data. /// </summary> /// <param name="loc"></param> /// <param name="allowPartialSelect">true - partial word selection allowed, false - only full words selection</param> /// <returns>true - is non empty selection, false - empty selection</returns> private bool CheckNonEmptySelection(RPoint loc, bool allowPartialSelect) { // full word selection is never empty if (!allowPartialSelect) return true; // if end selection location is near starting location then the selection is empty if (Math.Abs(_selectionStartPoint.X - loc.X) <= 1 && Math.Abs(_selectionStartPoint.Y - loc.Y) < 5) return false; // selection is empty if on same word and same index return _selectionStart != _selectionEnd || _selectionStartIndex != _selectionEndIndex; }
public override void Start(double x, double y) { _lastPoint = new RPoint(x, y); }
/// <summary> /// Clear the current selection. /// </summary> private void ClearSelection() { // clear drag and drop _dragDropData = null; ClearSelection(_root); _selectionStartOffset = -1; _selectionStartIndex = -1; _selectionEndOffset = -1; _selectionEndIndex = -1; _selectionStartPoint = RPoint.Empty; _selectionStart = null; _selectionEnd = null; }
/// <summary> /// Handle html text selection by mouse move over the html with left mouse button pressed.<br/> /// Calculate the words in the selected range and set their selected property. /// </summary> /// <param name="control">the control hosting the html to invalidate</param> /// <param name="loc">the mouse location</param> /// <param name="allowPartialSelect">true - partial word selection allowed, false - only full words selection</param> private void HandleSelection(RControl control, RPoint loc, bool allowPartialSelect) { // get the line under the mouse or nearest from the top var lineBox = DomUtils.GetCssLineBox(_root, loc); if (lineBox != null) { // get the word under the mouse var word = DomUtils.GetCssBoxWord(lineBox, loc); // if no word found under the mouse use the last or the first word in the line if (word == null && lineBox.Words.Count > 0) { if (loc.Y > lineBox.LineBottom) { // under the line word = lineBox.Words[lineBox.Words.Count - 1]; } else if (loc.X < lineBox.Words[0].Left) { // before the line word = lineBox.Words[0]; } else if (loc.X > lineBox.Words[lineBox.Words.Count - 1].Right) { // at the end of the line word = lineBox.Words[lineBox.Words.Count - 1]; } } // if there is matching word if (word != null) { if (_selectionStart == null) { // on start set the selection start word _selectionStartPoint = loc; _selectionStart = word; if (allowPartialSelect) CalculateWordCharIndexAndOffset(control, word, loc, true); } // always set selection end word _selectionEnd = word; if (allowPartialSelect) CalculateWordCharIndexAndOffset(control, word, loc, false); ClearSelection(_root); if (CheckNonEmptySelection(loc, allowPartialSelect)) { CheckSelectionDirection(); SelectWordsInRange(_root, _backwardSelection ? _selectionEnd : _selectionStart, _backwardSelection ? _selectionStart : _selectionEnd); } else { _selectionEnd = null; } _cursorChanged = true; control.SetCursorIBeam(); control.Invalidate(); } } }
/// <summary> /// Translates a <see cref="RPoint" /> by the negative of a specified size. /// </summary> /// <returns> /// The translated <see cref="RPoint" />. /// </returns> /// <param name="pt"> /// The <see cref="RPoint" /> to translate. /// </param> /// <param name="sz"> /// The <see cref="T:System.Drawing.SizeF" /> that specifies the numbers to subtract from the coordinates of /// <paramref /// name="pt" /> /// . /// </param> public static RPoint Subtract(RPoint pt, RSize sz) { return new RPoint(pt.X - sz.Width, pt.Y - sz.Height); }
/// <summary> /// Measures the bounds of box and children, recursively.<br/> /// Performs layout of the DOM structure creating lines by set bounds restrictions.<br/> /// </summary> /// <param name="g">Device context to use</param> protected virtual void PerformLayoutImp(RGraphics g) { if (Display != CssConstants.None) { RectanglesReset(); MeasureWordsSize(g); } if (IsBlock || Display == CssConstants.ListItem || Display == CssConstants.Table || Display == CssConstants.InlineTable || Display == CssConstants.TableCell) { // Because their width and height are set by CssTable if (Display != CssConstants.TableCell && Display != CssConstants.Table) { double width = ContainingBlock.Size.Width - ContainingBlock.ActualPaddingLeft - ContainingBlock.ActualPaddingRight - ContainingBlock.ActualBorderLeftWidth - ContainingBlock.ActualBorderRightWidth; if (Width != CssConstants.Auto && !string.IsNullOrEmpty(Width)) { width = CssValueParser.ParseLength(Width, width, this); } Size = new RSize(width, Size.Height); // must be separate because the margin can be calculated by percentage of the width Size = new RSize(width - ActualMarginLeft - ActualMarginRight, Size.Height); } if (Display != CssConstants.TableCell) { var prevSibling = DomUtils.GetPreviousSibling(this); double left = ContainingBlock.Location.X + ContainingBlock.ActualPaddingLeft + ActualMarginLeft + ContainingBlock.ActualBorderLeftWidth; double top = (prevSibling == null && ParentBox != null ? ParentBox.ClientTop : ParentBox == null ? Location.Y : 0) + MarginTopCollapse(prevSibling) + (prevSibling != null ? prevSibling.ActualBottom + prevSibling.ActualBorderBottomWidth : 0); Location = new RPoint(left, top); ActualBottom = top; } //If we're talking about a table here.. if (Display == CssConstants.Table || Display == CssConstants.InlineTable) { CssLayoutEngineTable.PerformLayout(g, this); } else { //If there's just inline boxes, create LineBoxes if (DomUtils.ContainsInlinesOnly(this)) { ActualBottom = Location.Y; CssLayoutEngine.CreateLineBoxes(g, this); //This will automatically set the bottom of this block } else if (_boxes.Count > 0) { foreach (var childBox in Boxes) { childBox.PerformLayout(g); } ActualRight = CalculateActualRight(); ActualBottom = MarginBottomCollapse(); } } } else { var prevSibling = DomUtils.GetPreviousSibling(this); if (prevSibling != null) { if (Location == RPoint.Empty) Location = prevSibling.Location; ActualBottom = prevSibling.ActualBottom; } } ActualBottom = Math.Max(ActualBottom, Location.Y + ActualHeight); CreateListItemBox(g); var actualWidth = Math.Max(GetMinimumWidth() + GetWidthMarginDeep(this), Size.Width < 90999 ? ActualRight - HtmlContainer.Root.Location.X : 0); HtmlContainer.ActualSize = CommonUtils.Max(HtmlContainer.ActualSize, new RSize(actualWidth, ActualBottom - HtmlContainer.Root.Location.Y)); }