/// <summary> /// Creates an empty SplashView. /// </summary> public SplashView() { document = new SplashDocument(); layout = new SplashLayout(document, this); paintOptions = new PaintOptions(); SetStyle(ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.Selectable | ControlStyles.UserMouse | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); base.BackColor = paintOptions.BackgroundColor; Padding = new Padding(5); AttachLayoutEvents(); InitializeContextMenu(); }
private void PaintLineForeground(DeviceContext deviceContext, PaintOptions paintOptions, ScriptLine* scriptLine, ScriptParagraph* scriptParagraph, int scriptRunIndex, int scriptRunCount, int* visualToLogicalMap, int xStartPosition, int xEndPosition, Rectangle layoutRect, bool isSelected, bool skipObjects) { int yCurrentBaseline = scriptLine->Y + scriptLine->Ascent; int xCurrentPosition = scriptLine->X; for (int i = 0; i < scriptRunCount; i++) { int logicalScriptRunIndex = visualToLogicalMap[currentLayoutRightToLeft ? scriptRunCount - i - 1 : i]; ScriptRun* scriptRun = scriptParagraph->ScriptRuns + logicalScriptRunIndex + scriptRunIndex; int measuredWidth; switch (scriptRun->RunKind) { case RunKind.Text: { Style style = document.LookupStyle(scriptRun->StyleIndex); ScriptMetrics scriptMetrics = deviceContext.SelectFont(style.Font); int glyphIndexInParagraph, glyphCount; measuredWidth = MeasureTextScriptRun(scriptParagraph, scriptRun, logicalScriptRunIndex == 0 ? scriptLine->TruncatedLeadingCharsCount : 0, logicalScriptRunIndex == scriptRunCount - 1 ? scriptLine->TruncatedTrailingCharsCount : 0, out glyphIndexInParagraph, out glyphCount); if (glyphCount > 0 && xCurrentPosition + measuredWidth > xStartPosition) { int x = currentLayoutRightToLeft ? layoutRect.Right - xCurrentPosition - measuredWidth : layoutRect.Left + xCurrentPosition; int y = layoutRect.Top + yCurrentBaseline - scriptRun->Ascent; deviceContext.SetTextColor(isSelected ? paintOptions.SelectedTextColor : style.Color); ScriptTextOut(deviceContext.HDC, ref scriptMetrics.ScriptCache, x, y, ExtTextOutOptions.NONE, null, &scriptRun->ScriptAnalysis, scriptParagraph->Glyphs + glyphIndexInParagraph, glyphCount, scriptParagraph->GlyphAdvanceWidths + glyphIndexInParagraph, null, scriptParagraph->GlyphOffsets + glyphIndexInParagraph); } break; } case RunKind.Object: { measuredWidth = MeasureObjectScriptRun(scriptRun); if (!skipObjects && xCurrentPosition + measuredWidth > xStartPosition) { int embeddedObjectCharIndex = scriptRun->CharIndexInParagraph + scriptParagraph->CharIndex; EmbeddedObjectHost embeddedObjectHost; if (embeddedObjectHosts.TryGetValue(embeddedObjectCharIndex, out embeddedObjectHost)) { if (embeddedObjectHost.RequiresPaint) { using (Graphics g = Graphics.FromHdc(deviceContext.HDC)) { Rectangle bounds = GetDrawingBoundsOfEmbeddedObject(embeddedObjectHost, layoutRect.Location); embeddedObjectHost.Paint(g, paintOptions, bounds, currentLayoutRightToLeft); } } } } break; } case RunKind.Tab: { measuredWidth = MeasureTabScriptRun(scriptRun, GetParagraphStyleAssumingItHasAtLeastOneRun(scriptParagraph), xCurrentPosition, false); break; } default: throw new NotSupportedException(); } xCurrentPosition += measuredWidth; if (xCurrentPosition >= xEndPosition) break; // can't fit any more runs within the clip rectangle } }
private void PaintLineBackgroundAndExcludeSelectedTextFromClipRegion(DeviceContext deviceContext, PaintOptions paintOptions, ScriptLine* scriptLine, ScriptParagraph* scriptParagraph, int scriptRunIndex, int scriptRunCount, int* visualToLogicalMap, int xStartPosition, int xEndPosition, Rectangle layoutRect, int selectedCharIndex, int selectedCharCount) { IntPtr brush = DeviceContext.GetStockObject(NativeConstants.DC_BRUSH); deviceContext.SetDCBrushColor(paintOptions.SelectedBackgroundColor); int yCurrentBaseline = scriptLine->Y + scriptLine->Ascent; int xCurrentPosition = scriptLine->X; for (int i = 0; i < scriptRunCount; i++) { int logicalScriptRunIndex = visualToLogicalMap[currentLayoutRightToLeft ? scriptRunCount - i - 1 : i]; ScriptRun* scriptRun = scriptParagraph->ScriptRuns + logicalScriptRunIndex + scriptRunIndex; int measuredWidth; switch (scriptRun->RunKind) { case RunKind.Text: { int glyphIndexInParagraph, glyphCount; int truncatedLeadingCharsCount = logicalScriptRunIndex == 0 ? scriptLine->TruncatedLeadingCharsCount : 0; int truncatedTrailingCharsCount = logicalScriptRunIndex == scriptRunCount - 1 ? scriptLine->TruncatedTrailingCharsCount : 0; measuredWidth = MeasureTextScriptRun(scriptParagraph, scriptRun, truncatedLeadingCharsCount, truncatedTrailingCharsCount, out glyphIndexInParagraph, out glyphCount); if (xCurrentPosition + measuredWidth > xStartPosition) { int scriptRunCharIndex = scriptParagraph->CharIndex + scriptRun->CharIndexInParagraph; int leadingCharIndex = scriptRunCharIndex + truncatedLeadingCharsCount; int trailingCharIndex = scriptRunCharIndex + scriptRun->CharCount - truncatedTrailingCharsCount; if (trailingCharIndex >= selectedCharIndex && leadingCharIndex <= selectedCharIndex + selectedCharCount) { int relativePositionOfSelection; if (leadingCharIndex >= selectedCharIndex) { relativePositionOfSelection = 0; } else { relativePositionOfSelection = MeasureTextScriptRun(scriptParagraph, scriptRun, truncatedLeadingCharsCount, truncatedTrailingCharsCount + trailingCharIndex - selectedCharIndex, out glyphIndexInParagraph, out glyphCount); } int measuredWidthOfSelection; if (trailingCharIndex <= selectedCharIndex + selectedCharCount) { measuredWidthOfSelection = measuredWidth - relativePositionOfSelection; } else { measuredWidthOfSelection = MeasureTextScriptRun(scriptParagraph, scriptRun, truncatedLeadingCharsCount + Math.Max(selectedCharIndex - leadingCharIndex, 0), truncatedTrailingCharsCount + trailingCharIndex - selectedCharIndex - selectedCharCount, out glyphIndexInParagraph, out glyphCount); } int x = currentLayoutRightToLeft ? layoutRect.Right - xCurrentPosition - measuredWidth : layoutRect.Left + xCurrentPosition; int y = layoutRect.Top + yCurrentBaseline - scriptRun->Ascent; if (scriptRun->ScriptAnalysis.fRTL) x += measuredWidth - relativePositionOfSelection - measuredWidthOfSelection; else x += relativePositionOfSelection; Rectangle selectedRect = new Rectangle(x, y, measuredWidthOfSelection, scriptRun->Height); deviceContext.FillRect(selectedRect, brush); deviceContext.ExcludeClipRect(selectedRect); } } break; } case RunKind.Object: case RunKind.Tab: { measuredWidth = scriptRun->RunKind == RunKind.Object ? MeasureObjectScriptRun(scriptRun) : MeasureTabScriptRun(scriptRun, GetParagraphStyleAssumingItHasAtLeastOneRun(scriptParagraph), xCurrentPosition, false); if (xCurrentPosition + measuredWidth > xStartPosition) { int leadingCharIndex = scriptParagraph->CharIndex + scriptRun->CharIndexInParagraph; int trailingCharIndex = leadingCharIndex + 1; if (trailingCharIndex >= selectedCharIndex && leadingCharIndex <= selectedCharIndex + selectedCharCount) { int x = currentLayoutRightToLeft ? layoutRect.Right - xCurrentPosition - measuredWidth : layoutRect.Left + xCurrentPosition; int y = layoutRect.Top + yCurrentBaseline - scriptRun->Ascent; Rectangle selectedRect = new Rectangle(x, y, measuredWidth, scriptRun->Height); deviceContext.FillRect(selectedRect, brush); // Don't exclude clip rect for objects and tabs. //deviceContext.ExcludeClipRect(selectedRect); } } break; } default: throw new NotSupportedException(); } xCurrentPosition += measuredWidth; if (xCurrentPosition >= xEndPosition) break; // can't fit any more runs within the clip rectangle } }
private void PaintRegion(DeviceContext deviceContext, Rectangle layoutRect, Rectangle clipRect, IntPtr clipRegion, PaintOptions paintOptions, int selectedCharIndex, int selectedCharCount) { int yStartPosition = clipRect.Top - layoutRect.Top; int yEndPosition = clipRect.Bottom - layoutRect.Top; int firstScriptLineIndex; ScriptLine* scriptLine = GetScriptLineAtYPositionOrNullIfNone(yStartPosition, out firstScriptLineIndex); if (scriptLine == null) return; ScriptLine* endScriptLine = GetScriptLineZero() + scriptLineBuffer.Count; int xStartPosition, xEndPosition; if (currentLayoutRightToLeft) { xStartPosition = layoutRect.Right - clipRect.Right; xEndPosition = layoutRect.Right - clipRect.Left; } else { xStartPosition = clipRect.Left - layoutRect.Left; xEndPosition = clipRect.Right - layoutRect.Left; } // Note: Selection may extend beyond the range of the layout if improper index and count // values were provided. This is ok since we only care about the intersection of the // selected range with actual range of characters on the lines. if (selectedCharCount < 0) { selectedCharIndex += selectedCharCount; selectedCharCount = -selectedCharCount; } deviceContext.SetBkMode(NativeConstants.TRANSPARENT); for (; scriptLine != endScriptLine && scriptLine->Y < yEndPosition; scriptLine++) { int scriptRunCount = scriptLine->ScriptRunCount; if (scriptRunCount != 0) { ScriptParagraph* scriptParagraph = GetScriptParagraph(deviceContext, scriptLine->ParagraphIndex); int scriptRunIndex = scriptLine->ScriptRunIndex; int* visualToLogicalMap = GetTempVisualToLogicalMap(scriptParagraph->ScriptRuns + scriptRunIndex, scriptRunCount); if (selectedCharCount == 0 || selectedCharIndex >= scriptParagraph->CharIndex + scriptParagraph->ScriptRuns[scriptRunIndex + scriptRunCount - 1].EndCharIndexInParagraph - scriptLine->TruncatedTrailingCharsCount || selectedCharIndex + selectedCharCount < scriptParagraph->CharIndex + scriptParagraph->ScriptRuns[scriptRunIndex].CharIndexInParagraph + scriptLine->TruncatedLeadingCharsCount) { deviceContext.SelectClipRegion(clipRegion); // No selection. Just paint the line as usual. PaintLineForeground(deviceContext, paintOptions, scriptLine, scriptParagraph, scriptRunIndex, scriptRunCount, visualToLogicalMap, xStartPosition, xEndPosition, layoutRect, false, false); } else { deviceContext.SelectClipRegion(clipRegion); // Paint background. PaintLineBackgroundAndExcludeSelectedTextFromClipRegion(deviceContext, paintOptions, scriptLine, scriptParagraph, scriptRunIndex, scriptRunCount, visualToLogicalMap, xStartPosition, xEndPosition, layoutRect, selectedCharIndex, selectedCharCount); // Paint all text and objects except in selected areas. PaintLineForeground(deviceContext, paintOptions, scriptLine, scriptParagraph, scriptRunIndex, scriptRunCount, visualToLogicalMap, xStartPosition, xEndPosition, layoutRect, false, false); // Invert the clip region. IntPtr lineRegion = DeviceContext.CreateRectRegion(clipRect); deviceContext.XorClipRegion(lineRegion); DeviceContext.DeleteObject(lineRegion); // Paint all text in selected areas. PaintLineForeground(deviceContext, paintOptions, scriptLine, scriptParagraph, scriptRunIndex, scriptRunCount, visualToLogicalMap, xStartPosition, xEndPosition, layoutRect, true, true); } } } }
/// <summary> /// Paints a region of text. /// </summary> /// <remarks> /// Be sure to update the layout before calling this method. /// </remarks> /// <param name="graphics">The graphics context.</param> /// <param name="layoutOrigin">The origin of the document layout area in the parent control.</param> /// <param name="clipRect">The clip rectangle of the region to paint in the device context.</param> /// <param name="paintOptions">The paint options.</param> /// <param name="selectedCharIndex">The index of the first selected character. Ignored if /// the number of selected characters is 0.</param> /// <param name="selectedCharCount">The number of selected characters or 0 if none. /// May be negative if the selection is reversed.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="graphics"/> or /// <paramref name="paintOptions"/> is null.</exception> public void Paint(Graphics graphics, Point layoutOrigin, Rectangle clipRect, PaintOptions paintOptions, int selectedCharIndex, int selectedCharCount) { if (graphics == null) throw new ArgumentNullException("graphics"); if (paintOptions == null) throw new ArgumentNullException("paintOptions"); recursionGuard.Do(() => { Rectangle layoutRect = new Rectangle(layoutOrigin.X, layoutOrigin.Y, currentLayoutWidth, currentLayoutHeight); Rectangle clippedLayoutRect = layoutRect; clippedLayoutRect.Intersect(clipRect); GraphicsState state = graphics.Save(); try { using (DeviceContext deviceContext = DeviceContext.CreateFromGraphics(graphics, scriptMetricsCache)) { IntPtr clipRegion = DeviceContext.CreateRectRegion(clippedLayoutRect); try { PaintRegion(deviceContext, layoutRect, clippedLayoutRect, clipRegion, paintOptions, selectedCharIndex, selectedCharCount); } finally { DeviceContext.DeleteObject(clipRegion); } } } finally { graphics.Restore(state); } }); }
public void Paint(Graphics g, PaintOptions paintOptions, Rectangle bounds, bool rightToLeft) { }
public void Paint(Graphics g, PaintOptions paintOptions, Rectangle bounds, bool rightToLeft) { g.DrawImage(embeddedImage.Image, bounds); }