/// <summary> /// Method used to draw the actual text data for the Control /// </summary> private void OnDisplayText(PaintEventArgs e) { if (reformatLines) { InitializeDisplayLines(); TotalDisplayLines = FormatLines(totalLines, 1, 0); UpdateScrollBar(TotalDisplayLines, 0); reformatLines = false; } try { var g = e.Graphics; //using "using" allow auto dispose int startY; var startX = 0; int linesToDraw; var buildString = new StringBuilder(); int curLine; int curForeColor, curBackColor; var pastForeColor = -1; //remember what is the text color before highlighting. Hint: the code is looping from left char to right char char[] ch; var displayRect = new Rectangle(0, 0, Width, Height); //Bitmap buffer = new Bitmap(this.Width, this.Height, e.Graphics); //g.Clear(IrcColor.colors[backColor]); if (BackgroundImage != null) { g.FillRectangle(new SolidBrush(TextColor.GetColor(backColor)), displayRect); g.DrawImage(BackgroundImage, displayRect.Left, displayRect.Top, displayRect.Width, displayRect.Height); } else g.FillRectangle(new SolidBrush(TextColor.GetColor(backColor)), displayRect); /*g.InterpolationMode = InterpolationMode.Low; g.SmoothingMode = SmoothingMode.HighSpeed; g.PixelOffsetMode = PixelOffsetMode.None; g.CompositingQuality = CompositingQuality.HighSpeed; g.TextRenderingHint = TextRenderingHint.SystemDefault;*/ if (totalLines == 0) return; else { var val = vScrollBar.Value; linesToDraw = Math.Min(showMaxLines, val); //Math.Min is faster and more readable than if-else, Reference:http://stackoverflow.com/questions/5478877/math-max-vs-inline-if-what-are-the-differences curLine = val - linesToDraw; if (singleLine) { startY = 0; linesToDraw = 1; curLine = 0; } else startY = Height - LineSize * linesToDraw - LineSize / 2; var lineCounter = 0; var underline = false; var isInUrl = false; var font = new Font(Font, FontStyle.Regular); var redline = -1; if (ShowUnreadLine) { for (int i = TotalDisplayLines - 1, j = 0; i >= 0; --i) { if (!displayLines[i].Previous) { ++j; if (j == unreadMarker) { redline = i; break; } } } } while (lineCounter < linesToDraw) //iterate over all rows { int i = 0, j = 0; var highlight = false; var oldHighlight = false; if (redline == curLine) { using (var p = new Pen(Color.Red)) { g.DrawLine(p, 0, startY, Width, startY); } } lineCounter++; curForeColor = displayLines[curLine].TextColor; var line = new StringBuilder(); line.Append(displayLines[curLine].Line); curBackColor = backColor; //check if in a url, cancel underline if not if (!isInUrl) { underline = false; font.SafeDispose(); font = new Font(Font, FontStyle.Regular); } if (line.Length > 0) { do //iterate over every character in a line { ch = line.ToString().Substring(i, 1).ToCharArray(); switch (ch[0]) { case TextColor.EmotChar: //this header is added by SaidLine.cs & SaidLineEx.cs //draws an emoticon //[]001 var emotNumber = Convert.ToInt32(line.ToString().Substring(i + 1, 3)); line.Remove(0, i + 4); i = -1; //draw text (that wasn't yet drawn up to *this* point) startX = DT(g, buildString, Font, startX, startY, curForeColor, curBackColor); //draw an emoticon g.DrawImage(TextImage.GetImage(emotNumber), startX, startY, 16, 16); startX += 16; buildString.Clear(); //reset the content (because we already draw it for user) break; case TextColor.UrlStart: startX = DT(g, buildString, font, startX, startY, curForeColor, curBackColor); buildString.Clear(); //remove whats drawn from string line.Remove(0, i); line.Remove(0, 1); i = -1; font.SafeDispose(); font = new Font(Font, FontStyle.Underline); isInUrl = true; break; case TextColor.UrlEnd: startX = DT(g, buildString, font, startX, startY, curForeColor, curBackColor); buildString.Clear(); //remove whats drawn from string line.Remove(0, i); line.Remove(0, 1); i = -1; font.SafeDispose(); font = new Font(Font, FontStyle.Regular); isInUrl = false; break; case TextColor.UnderlineChar: startX = DT(g, buildString, font, startX, startY, curForeColor, curBackColor); buildString.Clear(); //remove whats drawn from string line.Remove(0, i); line.Remove(0, 1); i = -1; underline = !underline; font.SafeDispose(); if (underline) font = new Font(Font, FontStyle.Underline); else { font = new Font(Font, FontStyle.Regular); } break; case TextColor.NewColorChar: //draw whats previously in the string startX = DT(g, buildString, font, startX, startY, curForeColor, curBackColor); //is slow for slow gpu IMO buildString.Clear(); //remove whats drawn from string line.Remove(0, i); //get the new fore and back colors if (!highlight) { curForeColor = Convert.ToInt32(line.ToString().Substring(1, 2)); curBackColor = Convert.ToInt32(line.ToString().Substring(3, 2)); //check to make sure that FC and BC are in range 0-32 if (curForeColor > TextColor.colorRange) curForeColor = displayLines[curLine].TextColor; if (curBackColor > TextColor.colorRange) curBackColor = backColor; } else //if highlighting then: { pastForeColor = Convert.ToInt32(line.ToString().Substring(1, 2)); //remember what color this text suppose to be (will be restored to the text on the right if highlighting only happen to text on the left) //check to make sure that FC and BC are in range 0-32 if (pastForeColor > TextColor.colorRange) pastForeColor = displayLines[curLine].TextColor; //only happen on exceptional case (this is only for safety, no significant whatsoever) } //remove the color codes from the string line.Remove(0, 5); i = -1; break; default: //curLine is "the line being processed here" (not user's line) //startHightLine is "the line where highlight start" //curHighLine is "the line where highlight end" //startHighChar is "the char where highlight start" //curHighChar is "the char where highlight end" //j is "the char being processed here" if (startHighLine >= 0 && //highlight is active ((curLine >= startHighLine && curLine <= curHighLine) || //processing in between highlight (if highlight is upward) (curLine <= startHighLine && curLine >= curHighLine))) //processing in between highlight (if highlight is downward) { if ((curLine > startHighLine && curLine < curHighLine) || (curLine == startHighLine && j >= startHighChar && (curLine <= curHighLine && j < curHighChar || curLine < curHighLine)) || (curLine == curHighLine && j < curHighChar && (curLine >= startHighLine && j >= startHighChar || curLine > startHighLine))) { highlight = true; } else if ((curLine < startHighLine && curLine > curHighLine) || (curLine == startHighLine && j < startHighChar && (curLine >= curHighLine && j >= curHighChar || curLine > curHighLine)) || (curLine == curHighLine && j >= curHighChar && (curLine <= startHighLine && j < startHighChar || curLine < startHighLine))) { highlight = true; } else highlight = false; } else highlight = false; ++j; if (highlight != oldHighlight) //at highlight border (where left & right is highlight or not highlight) { oldHighlight = highlight; //draw text (that wasn't yet drawn up to *this* point) startX = DT(g, buildString, font, startX, startY, curForeColor, curBackColor); buildString.Clear(); //reset the content (because we already draw it for user) //remove whats drawn from string line.Remove(0, i); i = 0; if (highlight) { pastForeColor = curForeColor; //remember previous text color curForeColor = TextColor.background; //white (defined in TextColor.cs) curBackColor = TextColor.text; //black (defined in TextColor.cs) } else { curForeColor = pastForeColor; //restore intended text color curBackColor = backColor; } } buildString.Append(ch[0]); break; } i++; } while (line.Length > 0 && i != line.Length); //loop character } //draw anything that is left over if (i == line.Length && line.Length > 0) DT(g, buildString, font, startX, startY, curForeColor, curBackColor); startY += LineSize; startX = 0; curLine++; buildString.Clear(); } //loop line font.Dispose(); //e.Graphics.DrawImageUnscaled(buffer, 0, 0); } // var coords = displayRect ButtonRenderer.DrawButton(g, new Rectangle(displayRect.Right - 200, displayRect.Top - 50, 100, 30), "Hide", Font, false, PushButtonState.Normal); buildString = null; } catch (Exception ee) { Trace.WriteLine("TextWindow OnDisplayText Error:" + ee.Message, ee.StackTrace); } }
/// <summary> /// Method used to draw the actual text data for the Control /// </summary> void OnDisplayText(PaintEventArgs e) { if (reformatLines) { InitializeDisplayLines(); TotalDisplayLines = FormatLines(totalLines, 1, 0); UpdateScrollBar(TotalDisplayLines,0); reformatLines = false; } try { using (var buffer = new Bitmap(Width, Height, PixelFormat.Format32bppPArgb)) using (var sf = StringFormat.GenericTypographic) using (var g = Graphics.FromImage(buffer)) //using "using" allow auto dispose { sf.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces; int startY; float startX = 0; int linesToDraw; var buildString = new StringBuilder(); int textSize; int curLine; int curForeColor, curBackColor; int pastForeColor=-1; //remember what is the text color before highlighting. Hint: the code is looping from left char to right char char[] ch; var displayRect = new Rectangle(0, 0, Width, Height); //Bitmap buffer = new Bitmap(this.Width, this.Height, e.Graphics); //g.Clear(IrcColor.colors[backColor]); if (BackgroundImage != null) { g.FillRectangle(new SolidBrush(TextColor.GetColor(backColor)), displayRect); g.DrawImage(BackgroundImage, displayRect.Left, displayRect.Top, displayRect.Width, displayRect.Height); } else g.FillRectangle(new SolidBrush(TextColor.GetColor(backColor)), displayRect); g.InterpolationMode = InterpolationMode.Low; g.SmoothingMode = SmoothingMode.HighSpeed; g.PixelOffsetMode = PixelOffsetMode.None; g.CompositingQuality = CompositingQuality.HighSpeed; g.TextRenderingHint = TextRenderingHint.SystemDefault; if (totalLines == 0) e.Graphics.DrawImageUnscaled(buffer, 0, 0); else { var val = vScrollBar.Value; linesToDraw = Math.Min(showMaxLines, val); //Math.Min is faster and more readable than if-else, Reference:http://stackoverflow.com/questions/5478877/math-max-vs-inline-if-what-are-the-differences curLine = val - linesToDraw; if (singleLine) { startY = 0; linesToDraw = 1; curLine = 0; } else startY = Height - (LineSize*linesToDraw) - (LineSize/2); var lineCounter = 0; var underline = false; var isInUrl = false; var font = new Font(Font.Name, Font.Size, Font.Style); var redline = -1; if (ShowUnreadLine) { for (int i = TotalDisplayLines - 1, j = 0; i >= 0; --i) { if (!displayLines[i].Previous) { ++j; if (j == unreadMarker) { redline = i; break; } } } } while (lineCounter < linesToDraw) //iterate over all rows { int i = 0, j = 0; var highlight = false; var oldHighlight = false; if (redline == curLine) { using (var p = new Pen(Color.Red)) { g.DrawLine(p, 0, startY, Width, startY); } } lineCounter++; curForeColor = displayLines[curLine].TextColor; var line = new StringBuilder(); line.Append(displayLines[curLine].Line); curBackColor = backColor; //check if in a url, cancel underline if not if (!isInUrl) { underline = false; font.SafeDispose(); font = new Font(Font.Name, Font.Size, Font.Style); } if (line.Length > 0) { do //iterate over every character in a line { using (SolidBrush backColorBrush = new SolidBrush(TextColor.GetColor(curBackColor))) //refresh backcolor { ch = line.ToString().Substring(i, 1).ToCharArray(); switch (ch[0]) { case TextColor.EmotChar: //this header is added by SaidLine.cs & SaidLineEx.cs //draws an emoticon //[]001 var emotNumber = Convert.ToInt32(line.ToString().Substring(i + 1, 3)); line.Remove(0, 3); if (!isInUrl) { //select the emoticon here var bm = TextImage.GetImage(emotNumber); if (curBackColor != backColor) { textSize = (int)g.MeasureString(buildString.ToString(), Font, 0, sf).Width + 1; var r = new Rectangle((int)startX, startY, textSize + 1, LineSize + 1); g.FillRectangle(backColorBrush, r); //draw white (or black) rectangle } g.DrawImage(bm, //draw an emoticon startX + g.MeasureString(buildString.ToString(), Font, 0, sf).Width, startY, 16, 16); using (var brush = new SolidBrush(TextColor.GetColor(curForeColor))) { g.DrawString(buildString.ToString(), //draw text (that wasn't yet drawn up to *this* point) Font, brush, startX, startY, sf); } startX += bm.Width + g.MeasureString(buildString.ToString(), Font, 0, sf).Width; buildString.Clear(); //reset the content (because we already draw it for user) } break; case TextColor.UrlStart: if (curBackColor != backColor) { textSize = (int)g.MeasureString(buildString.ToString(), Font, 0, sf).Width + 1; var r = new Rectangle((int)startX, startY, textSize + 1, LineSize + 1); g.FillRectangle(backColorBrush, r); } using (var brush = new SolidBrush(TextColor.GetColor(curForeColor))) { g.DrawString(buildString.ToString(), font, brush, startX, startY, sf); } // TextRenderer.DrawText(g, buildString.ToString(), font, new Point((int)startX, startY), TextColor.GetColor(curForeColor), TextColor.GetColor(curBackColor)); //is slow for slow gpu IMO startX += g.MeasureString(buildString.ToString(), font, 0, sf).Width; //textSizes[32] buildString.Clear(); //remove whats drawn from string line.Remove(0, i); line.Remove(0, 1); i = -1; font.SafeDispose(); font = new Font(Font.Name, Font.Size, Font.Style | FontStyle.Underline); isInUrl = true; break; case TextColor.UrlEnd: if (curBackColor != backColor) { textSize = (int)g.MeasureString(buildString.ToString(), font, 0, sf).Width + 1; var r = new Rectangle((int)startX, startY, textSize + 1, LineSize + 1); g.FillRectangle(backColorBrush, r); } // TextRenderer.DrawText(g, buildString.ToString(), font, new Point((int)startX, startY), TextColor.GetColor(curForeColor), TextColor.GetColor(curBackColor)); //is slow for slow gpu IMO using (var brush = new SolidBrush(TextColor.GetColor(curForeColor))) { g.DrawString(buildString.ToString(), font, brush, startX, startY, sf); } startX += g.MeasureString(buildString.ToString(), font, 0, sf).Width; //textSizes[32] buildString.Clear(); //remove whats drawn from string line.Remove(0, i); line.Remove(0, 1); i = -1; font.SafeDispose(); font = new Font(Font.Name, Font.Size, Font.Style); isInUrl = false; break; case TextColor.UnderlineChar: if (curBackColor != backColor) { textSize = (int)g.MeasureString(buildString.ToString(), font, 0, sf).Width + 1; var r = new Rectangle((int)startX, startY, textSize + 1, LineSize + 1); g.FillRectangle(backColorBrush, r); } // TextRenderer.DrawText(g, buildString.ToString(), font, new Point((int)startX, startY), TextColor.GetColor(curForeColor), TextColor.GetColor(curBackColor)); //is slow for slow gpu IMO using (var brush = new SolidBrush(TextColor.GetColor(curForeColor))) { g.DrawString(buildString.ToString(), font, brush, startX, startY, sf); } startX += g.MeasureString(buildString.ToString(), font, 0, sf).Width; //textSizes[32] buildString.Clear(); //remove whats drawn from string line.Remove(0, i); line.Remove(0, 1); i = -1; underline = !underline; font.SafeDispose(); if (underline) font = new Font(Font.Name, Font.Size, Font.Style | FontStyle.Underline); else {font = new Font(Font.Name, Font.Size, Font.Style);} break; case TextColor.NewColorChar: //draw whats previously in the string if (curBackColor != backColor) { textSize = (int)g.MeasureString(buildString.ToString(), font, 0, sf).Width + 1; var r = new Rectangle((int)startX, startY, textSize + 1, LineSize + 1); g.FillRectangle(backColorBrush, r); } // TextRenderer.DrawText(g, buildString.ToString(), font, new Point((int)startX, startY), TextColor.GetColor(curForeColor), TextColor.GetColor(curBackColor)); //is slow for slow gpu IMO using (var brush = new SolidBrush(TextColor.GetColor(curForeColor))) { g.DrawString(buildString.ToString(), font, brush, startX, startY, sf); } startX += g.MeasureString(buildString.ToString(), font, 0, sf).Width; //textSizes[32] buildString.Clear(); //remove whats drawn from string line.Remove(0, i); //get the new fore and back colors if (!highlight) { curForeColor = Convert.ToInt32(line.ToString().Substring(1, 2)); curBackColor = Convert.ToInt32(line.ToString().Substring(3, 2)); //check to make sure that FC and BC are in range 0-32 if (curForeColor > TextColor.colorRange) curForeColor = displayLines[curLine].TextColor; if (curBackColor > TextColor.colorRange) curBackColor = backColor; } else //if highlighting then: { pastForeColor = Convert.ToInt32(line.ToString().Substring(1, 2)); //remember what color this text suppose to be (will be restored to the text on the right if highlighting only happen to text on the left) //check to make sure that FC and BC are in range 0-32 if (pastForeColor > TextColor.colorRange) pastForeColor = displayLines[curLine].TextColor; //only happen on exceptional case (this is only for safety, no significant whatsoever) } //remove the color codes from the string line.Remove(0, 5); i = -1; break; default: //random symbol safety check (symbols to skip drawing) if((int)ch[0] > Int16.MaxValue) //random symbol can mess up graphic object "g" in Linux! which cause nothing to be drawn after the symbol { if (curBackColor != backColor) { textSize = (int)g.MeasureString(buildString.ToString(), Font, 0, sf).Width + 1; var r = new Rectangle((int)startX, startY, textSize + 1, LineSize + 1); g.FillRectangle(backColorBrush, r); } using (var brush = new SolidBrush(TextColor.GetColor(curForeColor))) { g.DrawString(buildString.ToString(), font, brush, startX, startY, sf); } startX += g.MeasureString(buildString.ToString(), font, 0, sf).Width; float symbolWidth; using (var tmpBuffer = new Bitmap(LineSize,LineSize, PixelFormat.Format32bppPArgb)) using (var tmpG = Graphics.FromImage(tmpBuffer)) //temporary graphic object that can be messed up independently { var randomChar = ch[0].ToString(); symbolWidth = tmpG.MeasureString(randomChar, font, 0, sf).Width; if (symbolWidth > 0) //don't draw when symbol width == 0 (symptom obtained from trial-n-error) { using (var brush = new SolidBrush(TextColor.GetColor(curForeColor))) { g.DrawString(randomChar, font, brush, startX, startY, sf); } } } startX += symbolWidth; line.Remove(0, i); line.Remove(0, 1); i= -1; buildString.Clear(); break; } //curLine is "the line being processed here" (not user's line) //startHightLine is "the line where highlight start" //curHighLine is "the line where highlight end" //startHighChar is "the char where highlight start" //curHighChar is "the char where highlight end" //j is "the char being processed here" if (startHighLine >= 0 && //highlight is active ((curLine >= startHighLine && curLine <= curHighLine) || //processing in between highlight (if highlight is upward) (curLine <= startHighLine && curLine >= curHighLine))) //processing in between highlight (if highlight is downward) { if ((curLine > startHighLine && curLine < curHighLine) || (curLine == startHighLine && j >= startHighChar && (curLine <= curHighLine && j < curHighChar || curLine < curHighLine)) || (curLine == curHighLine && j < curHighChar && (curLine >= startHighLine && j >= startHighChar || curLine > startHighLine))) { highlight = true; } else if ((curLine < startHighLine && curLine > curHighLine) || (curLine == startHighLine && j < startHighChar && (curLine >= curHighLine && j >= curHighChar || curLine > curHighLine)) || (curLine == curHighLine && j >= curHighChar && (curLine <= startHighLine && j < startHighChar || curLine < startHighLine))) { highlight = true; } else highlight = false; } else highlight = false; ++j; if (highlight != oldHighlight) //at highlight border (where left & right is highlight or not highlight) { oldHighlight = highlight; //draw whats previously in the string if (curBackColor != backColor) { textSize = (int)g.MeasureString(buildString.ToString(), font, 0, sf).Width + 1; var r = new Rectangle((int)startX, startY, textSize + 1, LineSize + 1); g.FillRectangle(backColorBrush, r); //draw black (or white) rectangle } /* //GDI example: TextRenderer.DrawText(g, buildString.ToString(), font, new Point((int)startX, startY), TextColor.GetColor(curForeColor), TextColor.GetColor(curBackColor)); */ using (var solidBrush = new SolidBrush(TextColor.GetColor(curForeColor))) { g.DrawString(buildString.ToString(), //draw text (that wasn't yet drawn up to *this* point) font, solidBrush, startX, startY, sf); } startX += g.MeasureString(buildString.ToString(), font, 0, sf).Width; //textSizes[32] buildString.Clear();//reset the content (because we already draw it for user) //remove whats drawn from string line.Remove(0, i); i = 0; if (highlight) { pastForeColor = curForeColor; //remember previous text color curForeColor = TextColor.background; //white (defined in TextColor.cs) curBackColor = TextColor.text; //black (defined in TextColor.cs) } else { curForeColor = pastForeColor; //restore intended text color curBackColor = backColor; } } buildString.Append(ch[0]); break; } i++; } } while (line.Length > 0 && i != line.Length); //loop character } //draw anything that is left over if (i == line.Length && line.Length > 0) { if (curBackColor != backColor) { textSize = (int)g.MeasureString(buildString.ToString(), font, 0, sf).Width + 1; var r = new Rectangle((int)startX, startY, textSize + 1, LineSize + 1); using (var brush = new SolidBrush(TextColor.GetColor(curBackColor))) g.FillRectangle(brush, r); } // TextRenderer.DrawText(g, buildString.ToString(), font, new Point((int)startX, startY), TextColor.GetColor(curForeColor), TextColor.GetColor(curBackColor)); using (var brush = new SolidBrush(TextColor.GetColor(curForeColor))) { g.DrawString(buildString.ToString(), font, brush, startX, startY, sf); } } startY += LineSize; startX = 0; curLine++; buildString.Clear(); } //loop line font.Dispose(); e.Graphics.DrawImageUnscaled(buffer, 0, 0); } // var coords = displayRect ButtonRenderer.DrawButton(g, new Rectangle(displayRect.Right - 200, displayRect.Top - 50, 100, 30), "Hide", Font, false, PushButtonState.Normal); buildString = null; } } catch (Exception ee) { Trace.WriteLine("TextWindow OnDisplayText Error:" + ee.Message, ee.StackTrace); } }