/// <summary> /// Get css word 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 at</param> /// <returns>css word box if exists or null</returns> public static CssRect GetCssBoxWord(CssBox box, Point location) { if (box != null && box.Visibility == CssConstants.Visible) { if (box.LineBoxes.Count > 0) { foreach (CssLineBox lineBox in box.LineBoxes) { CssRect wordBox = GetCssBoxWord(lineBox, location); if (wordBox != null) { return(wordBox); } } } if (box.ClientRectangle.IsEmpty || box.ClientRectangle.Contains(location)) { foreach (CssBox childBox in box.Boxes) { CssRect foundWord = GetCssBoxWord(childBox, location); if (foundWord != null) { return(foundWord); } } } } return(null); }
/// <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="useGdiPlusTextRendering">if to use GDI+ text rendering</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(Control control, CssRect word, Point loc, bool inclusive, bool useGdiPlusTextRendering, out int selectionIndex, out float 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 var font = word.OwnerBox.ActualFont; using (var g = new WinGraphics(control.CreateGraphics(), useGdiPlusTextRendering)) { int charFit; int charFitWidth; var maxWidth = offset + (inclusive ? 0 : 1.5f * word.LeftGlyphPadding); g.MeasureString(word.Text, font, maxWidth, out charFit, out charFitWidth); selectionIndex = charFit; selectionOffset = charFitWidth; } } }
/// <summary> /// Select all the words that are between <paramref name="selectionStart"/> word and <paramref name="selectionEnd"/> word in the DOM hierarchy. /// </summary> /// <param name="box">the current traversal node</param> /// <param name="selectionStart">selection start word limit</param> /// <param name="selectionEnd">selection end word limit</param> /// <param name="inSelection">used to know the traversal is currently in selected range</param> /// <returns></returns> private bool SelectWordsInRange(CssBox box, CssRect selectionStart, CssRect selectionEnd, ref bool inSelection) { foreach (var boxWord in box.Words) { if (!inSelection && boxWord == selectionStart) { inSelection = true; } if (inSelection) { boxWord.Selection = this; if (selectionStart == selectionEnd || boxWord == selectionEnd) { return(true); } } } foreach (var childBox in box.Boxes) { if (SelectWordsInRange(childBox, selectionStart, selectionEnd, ref inSelection)) { return(true); } } return(false); }
/// <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> /// Show context menu clicked on given rectangle. /// </summary> /// <param name="parent">the parent control to show the context menu on</param> /// <param name="rect">the rectangle that was clicked to show context menu</param> /// <param name="link">the link that was clicked to show context menu on</param> public void ShowContextMenu(RControl parent, CssRect rect, CssBox link) { try { DisposeContextMenu(); _parentControl = parent; _currentRect = rect; _currentLink = link; _contextMenu = _htmlContainer.Adapter.GetContextMenu(); if (rect != null) { bool isVideo = false; if (link != null) { isVideo = link is CssBoxFrame && ((CssBoxFrame)link).IsVideo; var linkExist = !string.IsNullOrEmpty(link.HrefLink); _contextMenu.AddItem(isVideo ? _openVideo : _openLink, linkExist, OnOpenLinkClick); if (_htmlContainer.IsSelectionEnabled) { _contextMenu.AddItem(isVideo ? _copyVideoUrl : _copyLink, linkExist, OnCopyLinkClick); } _contextMenu.AddDivider(); } if (rect.IsImage && !isVideo) { _contextMenu.AddItem(_saveImage, rect.Image != null, OnSaveImageClick); if (_htmlContainer.IsSelectionEnabled) { _contextMenu.AddItem(_copyImageLink, !string.IsNullOrEmpty(_currentRect.OwnerBox.GetAttribute("src")), OnCopyImageLinkClick); _contextMenu.AddItem(_copyImage, rect.Image != null, OnCopyImageClick); } _contextMenu.AddDivider(); } if (_htmlContainer.IsSelectionEnabled) { _contextMenu.AddItem(_copy, rect.Selected, OnCopyClick); } } if (_htmlContainer.IsSelectionEnabled) { _contextMenu.AddItem(_selectAll, true, OnSelectAllClick); } if (_contextMenu.ItemsCount > 0) { _contextMenu.RemoveLastDivider(); _contextMenu.Show(parent, parent.MouseLocation); } } catch (Exception ex) { _htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to show context menu", ex); } }
/// <summary> /// Dispose of the last used context menu. /// </summary> private void DisposeContextMenu() { try { if (_contextMenu != null) { _contextMenu.Dispose(); } _contextMenu = null; _parentControl = null; _currentRect = null; _currentLink = null; } catch {} }
/// <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 charecter index and offset by charecters for the given word and given offset. /// 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 begining.<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="selectionIndex">return the index of the char under the location</param> /// <param name="selectionOffset">return the offset of the char under the location</param> /// <param name="inclusive">is to include the first charecter in the calculation</param> private static void CalculateWordCharIndexAndOffset(Control control, CssRect word, Point loc, bool inclusive, out int selectionIndex, out float selectionOffset) { selectionIndex = 0; selectionOffset = 0.1f; 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 selectionIndex = word.Text.Length; selectionOffset = word.OwnerBox.ActualWordSpacing / 2f; using (var g = control.CreateGraphics()) { for (int i = 1; i <= word.Text.Length; i++) { var sf = new StringFormat(); sf.SetMeasurableCharacterRanges(new[] { new CharacterRange(0, i) }); var regions = g.MeasureCharacterRanges(word.Text, word.OwnerBox.ActualFont, new RectangleF(0, 0, float.MaxValue, float.MaxValue), sf); SizeF s = regions[0].GetBounds(g).Size; if (!inclusive) { selectionOffset = s.Width + (s.Width / i / 15f); } if (s.Width > offset) { selectionIndex = i - (inclusive ? 1 : 0); break; } selectionOffset = s.Width + (s.Width / i / 15f); } } } }
/// <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> /// Clear the current selection. /// </summary> public void ClearSelection() { // clear drag and drop this._dragDropData = null; ClearSelection(this._root); this._selectionStartOffset = -1; this._selectionStartIndex = -1; this._selectionEndOffset = -1; this._selectionEndIndex = -1; this._selectionStartPoint = RPoint.Empty; this._selectionStart = null; this._selectionEnd = null; }
/// <summary> /// Get the selected word with respect to partial selected words. /// </summary> /// <param name="rect">the word to append</param> /// <param name="selectedText">is to get selected text or all the text in the word</param> private static string GetSelectedWord(CssRect rect, bool selectedText) { if (selectedText && rect.SelectedStartIndex > -1 && rect.SelectedEndIndexOffset > -1) { return(rect.Text.Substring(rect.SelectedStartIndex, rect.SelectedEndIndexOffset - rect.SelectedStartIndex)); } if (selectedText && rect.SelectedStartIndex > -1) { return(rect.Text.Substring(rect.SelectedStartIndex) + (rect.HasSpaceAfter ? " " : "")); } if (selectedText && rect.SelectedEndIndexOffset > -1) { return(rect.Text.Substring(0, rect.SelectedEndIndexOffset)); } var whitespaceBefore = rect.OwnerBox.Words[0] == rect?IsBoxHasWhitespace(rect.OwnerBox) : rect.HasSpaceBefore; return((whitespaceBefore ? " " : "") + rect.Text + (rect.HasSpaceAfter ? " " : "")); }
/// <summary> /// Calculate the character index and offset by characters for the given word and given offset.<br/> /// <seealso cref="CalculateWordCharIndexAndOffset(Control, CssRect, Point, bool, bool, out int, out float)"/>. /// </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(Control control, CssRect word, Point loc, bool selectionStart) { int selectionIndex; float selectionOffset; CalculateWordCharIndexAndOffset(control, word, loc, selectionStart, _root.HtmlContainer.UseGdiPlusTextRendering, out selectionIndex, out selectionOffset); if (selectionStart) { _selectionStartIndex = selectionIndex; _selectionStartOffset = selectionOffset; } else { _selectionEndIndex = selectionIndex; _selectionEndOffset = selectionOffset; } }
/// <summary> /// Calculate the character index and offset by characters for the given word and given offset.<br/> /// <seealso cref="CalculateWordCharIndexAndOffset(RControl,HtmlRenderer.Core.Dom.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> /// 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(Control parent, Point loc) { if (_root.HtmlContainer.IsSelectionEnabled && _mouseDownInControl && (Control.MouseButtons & MouseButtons.Left) != 0) { 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. CssBox link = DomUtils.GetLinkBox(_root, loc); if (link != null) { _cursorChanged = true; parent.Cursor = Cursors.Hand; } else if (_root.HtmlContainer.IsSelectionEnabled) { CssRect 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)); parent.Cursor = _cursorChanged ? Cursors.IBeam : Cursors.Default; } else if (_cursorChanged) { parent.Cursor = Cursors.Default; } } }
/// <summary> /// Get the selected word with respect to partial selected words. /// </summary> /// <param name="rect">the word to append</param> /// <param name="selectedText">is to get selected text or all the text in the word</param> private static string GetSelectedWord(CssRect rect, bool selectedText) { if (selectedText && rect.SelectedStartIndex > -1 && rect.SelectedEndIndexOffset > -1) { return(rect.Text.Substring(rect.SelectedStartIndex, rect.SelectedEndIndexOffset - rect.SelectedStartIndex)); } else if (selectedText && rect.SelectedStartIndex > -1) { return(rect.Text.Substring(rect.SelectedStartIndex) + (rect.HasSpaceAfter ? " " : "")); } else if (selectedText && rect.SelectedEndIndexOffset > -1) { return(rect.Text.Substring(0, rect.SelectedEndIndexOffset)); } else { return((rect.HasSpaceBefore ? " " : "") + rect.Text + (rect.HasSpaceAfter ? " " : "")); } }
/// <summary> /// Find the css line box that the given word is in. /// </summary> /// <param name="word">the word to search for it's line box</param> /// <returns>line box that the word is in</returns> public static CssLineBox GetCssLineBoxByWord(CssRect word) { var box = word.OwnerBox; while (box.LineBoxes.Count == 0) { box = box.ParentBox; } foreach (var lineBox in box.LineBoxes) { foreach (var lineWord in lineBox.Words) { if (lineWord == word) { return(lineBox); } } } return(box.LineBoxes[0]); }
/// <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(Control parent, Point 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 && (Control.MouseButtons & MouseButtons.Left) != 0) { CssRect word = DomUtils.GetCssBoxWord(_root, loc); if (word != null && word.Selected) { _mouseDownOnSelectedWord = true; } else { clear = true; } } else if ((Control.MouseButtons & MouseButtons.Right) != 0) { CssRect rect = DomUtils.GetCssBoxWord(_root, loc); CssBox link = DomUtils.GetLinkBox(_root, loc); if (_root.HtmlContainer.IsContextMenuEnabled) { _contextMenuHandler.ShowContextMenu(parent, rect, link); } clear = rect == null || !rect.Selected; } } if (clear) { ClearSelection(); parent.Invalidate(); } }
/// <summary> /// Show context menu clicked on given rectangle. /// </summary> /// <param name="parent">the parent control to show the context menu on</param> /// <param name="rect">the rectangle that was clicked to show context menu</param> /// <param name="link">the link that was clicked to show context menu on</param> public void ShowContextMenu(Control parent, CssRect rect, CssBox link) { try { DisposeContextMenu(); _parentControl = parent; _currentRect = rect; _currentLink = link; _contextMenu = new ContextMenuStrip(); _contextMenu.ShowImageMargin = false; if (rect != null) { bool isVideo = false; if (link != null) { isVideo = link is CssBoxFrame && ((CssBoxFrame)link).IsVideo; var openLink = _contextMenu.Items.Add(isVideo ? _openVideo : _openLink, null, OnOpenLinkClick); if (_htmlContainer.IsSelectionEnabled) { var copyLink = _contextMenu.Items.Add(isVideo ? _copyVideoUrl : _copyLink, null, OnCopyLinkClick); copyLink.Enabled = !string.IsNullOrEmpty(link.HrefLink); } openLink.Enabled = !string.IsNullOrEmpty(link.HrefLink); _contextMenu.Items.Add("-"); } if (rect.IsImage && !isVideo) { var saveImage = _contextMenu.Items.Add(_saveImage, null, OnSaveImageClick); if (_htmlContainer.IsSelectionEnabled) { var copyImageUrl = _contextMenu.Items.Add(_copyImageLink, null, OnCopyImageLinkClick); var copyImage = _contextMenu.Items.Add(_copyImage, null, OnCopyImageClick); copyImageUrl.Enabled = !string.IsNullOrEmpty(_currentRect.OwnerBox.GetAttribute("src")); copyImage.Enabled = rect.Image != null; } saveImage.Enabled = rect.Image != null; _contextMenu.Items.Add("-"); } if (_htmlContainer.IsSelectionEnabled) { var copy = _contextMenu.Items.Add(_copy, null, OnCopyClick); copy.Enabled = rect.Selected; } } if (_htmlContainer.IsSelectionEnabled) { _contextMenu.Items.Add(_selectAll, null, OnSelectAllClick); } if (_contextMenu.Items.Count > 0) { if (_contextMenu.Items[_contextMenu.Items.Count - 1].Text == string.Empty) { _contextMenu.Items.RemoveAt(_contextMenu.Items.Count - 1); } _contextMenu.Show(parent, parent.PointToClient(Control.MousePosition)); } } catch (Exception ex) { _htmlContainer.ReportError(HtmlRenderErrorType.ContextMenu, "Failed to show context menu", ex); } }
/// <summary> /// Select all the words that are between <paramref name="selectionStart"/> word and <paramref name="selectionEnd"/> word in the DOM hierarchy.<br/> /// </summary> /// <param name="root">the root of the DOM sub-tree the selection is in</param> /// <param name="selectionStart">selection start word limit</param> /// <param name="selectionEnd">selection end word limit</param> private void SelectWordsInRange(CssBox root, CssRect selectionStart, CssRect selectionEnd) { bool inSelection = false; SelectWordsInRange(root, selectionStart, selectionEnd, ref inSelection); }
/// <summary> /// The selection start offset if the first selected word is partially selected (-1 if not selected or fully selected)<br/> /// if the given word is not starting or ending selection word -1 is returned as full word selection is in place. /// </summary> /// <remarks> /// Handles backward selecting by returning the selection end data instead of start. /// </remarks> /// <param name="word">the word to return the selection start offset for</param> public float GetSelectedStartOffset(CssRect word) { return(word == (_backwardSelection ? _selectionEnd : _selectionStart) ? (_backwardSelection ? _selectionEndOffset : _selectionStartOffset) : -1); }
/// <summary> /// The selection start index if the first selected word is partially selected (-1 if not selected or fully selected)<br/> /// if the given word is not starting or ending selection word -1 is returned as full word selection is in place. /// </summary> /// <remarks> /// Handles backward selecting by returning the selection end data instead of start. /// </remarks> /// <param name="word">the word to return the selection start index for</param> /// <returns>data value or -1 if not applicable</returns> public int GetSelectingStartIndex(CssRect word) { return(word == (this._backwardSelection ? this._selectionEnd : this._selectionStart) ? (this._backwardSelection ? this._selectionEndIndex : this._selectionStartIndex) : -1); }
/// <summary> /// The selection end offset if the last selected word is partially selected (-1 if not selected or fully selected)<br/> /// if the given word is not starting or ending selection word -1 is returned as full word selection is in place. /// </summary> /// <remarks> /// Handles backward selecting by returning the selection end data instead of start. /// </remarks> /// <param name="word">the word to return the selection end offset for</param> public double GetSelectedEndOffset(CssRect word) { return(word == (_backwardSelection ? _selectionStart : _selectionEnd) ? (_backwardSelection ? _selectionStartOffset : _selectionEndOffset) : -1); }
/// <summary> /// The selection end index if the last selected word is partially selected (-1 if not selected or fully selected)<br/> /// if the given word is not starting or ending selection word -1 is returned as full word selection is in place. /// </summary> /// <remarks> /// Handles backward selecting by returning the selection end data instead of start. /// </remarks> /// <param name="word">the word to return the selection end index for</param> public int GetSelectedEndIndexOffset(CssRect word) { return(word == (_backwardSelection ? _selectionStart : _selectionEnd) ? (_backwardSelection ? _selectionStartIndex : _selectionEndIndex) : -1); }
/// <summary> /// The selection start index if the first selected word is partially selected (-1 if not selected or fully selected)<br/> /// if the given word is not starting or ending selection word -1 is returned as full word selection is in place. /// </summary> /// <remarks> /// Handles backward selecting by returning the selection end data instead of start. /// </remarks> /// <param name="word">the word to return the selection start index for</param> /// <returns>data value or -1 if not applicable</returns> public int GetSelectingStartIndex(CssRect word) { return(word == (_backwardSelection ? _selectionEnd : _selectionStart) ? (_backwardSelection ? _selectionEndIndex : _selectionStartIndex) : -1); }
/// <summary> /// Outlines a rectangular area with the currently set color /// </summary> /// <param name="LineThickness">Thickness of the line in pixels</param> /// <param name="Rect">A rectangular area</param> public abstract void Draw_Rect(int LineThickness, CssRect Rect);
/// <summary> /// The selection start offset if the first selected word is partially selected (-1 if not selected or fully selected)<br/> /// if the given word is not starting or ending selection word -1 is returned as full word selection is in place. /// </summary> /// <remarks> /// Handles backward selecting by returning the selection end data instead of start. /// </remarks> /// <param name="word">the word to return the selection start offset for</param> public double GetSelectedStartOffset(CssRect word) { return(word == (this._backwardSelection ? this._selectionEnd : this._selectionStart) ? (this._backwardSelection ? this._selectionEndOffset : this._selectionStartOffset) : -1); }
/// <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> /// Fills a rectangular area with the currently set color /// </summary> /// <param name="Rect">A rectangular area</param> public abstract void Fill_Rect(CssRect Rect);