public static void DrawMessage(object graphics, Common.Message message, int xOffset, int yOffset, Selection selection, int currentLine, bool drawText, List <GifEmoteState> gifEmotesOnScreen = null, bool allowMessageSeperator = true) { message.X = xOffset; message.Y = yOffset; var g = (Graphics)graphics; var spaceWidth = GuiEngine.Current.MeasureStringSize(g, FontType.Medium, " ").Width; g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; g.InterpolationMode = InterpolationMode.HighQualityBicubic; message.X = xOffset; var textColor = App.ColorScheme.Text; Brush highlightBrush = null; if (message.HasAnyHighlightType(HighlightType.Highlighted)) { highlightBrush = App.ColorScheme.ChatBackgroundHighlighted; } else if (message.HasAnyHighlightType(HighlightType.Resub)) { highlightBrush = App.ColorScheme.ChatBackgroundResub; } else if (message.HasAnyHighlightType(HighlightType.Whisper)) { highlightBrush = App.ColorScheme.ChatBackgroundWhisper; } if (highlightBrush != null) { g.FillRectangle(highlightBrush, 0, yOffset, g.ClipBounds.Width, message.Height); } g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.Default; for (var i = 0; i < message.Words.Count; i++) { var word = message.Words[i]; if (word.Type == SpanType.Text) { if (drawText) { var font = Fonts.GetFont(word.Font); var color = textColor; if (word.Color.HasValue) { var hsl = word.Color.Value; if (App.ColorScheme.IsLightTheme) { if (hsl.Luminosity > 0.5f) { hsl = hsl.WithLuminosity(0.5f); } } else { if (hsl.Luminosity < 0.3f) { hsl = hsl.WithLuminosity(0.3f); } } float r, _g, b; hsl.ToRGB(out r, out _g, out b); color = Color.FromArgb((int)(r * 255), (int)(_g * 255), (int)(b * 255)); } if (word.SplitSegments == null) { TextRenderer.DrawText(g, (string)word.Value, font, new Point(xOffset + word.X, yOffset + word.Y), color, App.DefaultTextFormatFlags); } else { var segments = word.SplitSegments; for (var x = 0; x < segments.Length; x++) { TextRenderer.DrawText(g, segments[x].Item1, font, new Point(xOffset + segments[x].Item2.X, yOffset + segments[x].Item2.Y), color, App.DefaultTextFormatFlags); } } } } else if (word.Type == SpanType.LazyLoadedImage) { var emote = (LazyLoadedImage)word.Value; var img = (Image)emote.Image; if (img != null) { lock (img) { g.DrawImage(img, word.X + xOffset, word.Y + yOffset, word.Width, word.Height); } } else { //g.DrawRectangle(Pens.Red, xOffset + word.X, word.Y + yOffset, word.Width, word.Height); } } //else if (word.Type == SpanType.Image) //{ // var img = (Image)word.Value; // if (img != null) // g.DrawImage(img, word.X + xOffset, word.Y + yOffset, word.Width, word.Height); //} } Action <int, bool> addWordToGifList = (i, selected) => { var word = message.Words[i]; var words = new List <Word>(); for (var j = i - 1; j >= 0; j--) { if (message.Words[j].Intersects(word)) { words.Insert(0, message.Words[j]); } else { break; } } words.Add(word); for (var j = i + 1; j < message.Words.Count; j++) { if (message.Words[j].Intersects(word)) { words.Add(message.Words[j]); } else { break; } } gifEmotesOnScreen?.Add(new GifEmoteState(word.X + xOffset, word.Y + yOffset, word.Width, word.Height, words, selected, message.HighlightType, message.Disabled, yOffset, xOffset)); }; if (selection != null && !selection.IsEmpty && selection.First.MessageIndex <= currentLine && selection.Last.MessageIndex >= currentLine) { g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None; var first = selection.First; var last = selection.Last; for (var i = 0; i < message.Words.Count; i++) { var word = message.Words[i]; if ((currentLine != first.MessageIndex || i >= first.WordIndex) && (currentLine != last.MessageIndex || i <= last.WordIndex)) { if (word.Type == SpanType.Text) { for (var j = 0; j < (word.SplitSegments?.Length ?? 1); j++) { if ((first.MessageIndex == currentLine && first.WordIndex == i && first.SplitIndex > j) || (last.MessageIndex == currentLine && last.WordIndex == i && last.SplitIndex < j)) { continue; } var split = word.SplitSegments?[j]; var text = split?.Item1 ?? (string)word.Value; var rect = split?.Item2 ?? new CommonRectangle(word.X, word.Y, word.Width, word.Height); var textLength = text.Length; var offset = (first.MessageIndex == currentLine && first.SplitIndex == j && first.WordIndex == i) ? first.CharIndex : 0; var length = ((last.MessageIndex == currentLine && last.SplitIndex == j && last.WordIndex == i) ? last.CharIndex : textLength) - offset; if (offset == 0 && length == text.Length) { g.FillRectangle(_selectionBrush, rect.X + xOffset, rect.Y + yOffset, GuiEngine.Current.MeasureStringSize(App.UseDirectX ? null : g, word.Font, text) .Width + spaceWidth - 1, rect.Height); } else if (offset == text.Length) { g.FillRectangle(_selectionBrush, rect.X + xOffset + rect.Width, rect.Y + yOffset, spaceWidth, rect.Height); } else { g.FillRectangle(_selectionBrush, rect.X + xOffset + (offset == 0 ? 0 : GuiEngine.Current.MeasureStringSize(App.UseDirectX ? null : g, word.Font, text.Remove(offset)).Width), rect.Y + yOffset, GuiEngine.Current.MeasureStringSize(App.UseDirectX ? null : g, word.Font, text.Substring(offset, length)).Width + ((last.MessageIndex > currentLine || last.SplitIndex > j || last.WordIndex > i) ? spaceWidth : 0), rect.Height); } } } //else if (word.Type == SpanType.Image) //{ // var textLength = 2; // var offset = (first.MessageIndex == currentLine && first.WordIndex == i) // ? first.CharIndex // : 0; // var length = ((last.MessageIndex == currentLine && last.WordIndex == i) // ? last.CharIndex // : textLength) - offset; // g.FillRectangle(_selectionBrush, word.X + xOffset + (offset == 0 ? 0 : word.Width), // word.Y + yOffset, // (offset == 0 ? word.Width : 0) + (offset + length == 2 ? spaceWidth : 0) - 1, // word.Height); //} else if (word.Type == SpanType.LazyLoadedImage) { var textLength = 2; var offset = (first.MessageIndex == currentLine && first.WordIndex == i) ? first.CharIndex : 0; var length = ((last.MessageIndex == currentLine && last.WordIndex == i) ? last.CharIndex : textLength) - offset; var emote = (LazyLoadedImage)word.Value; if (emote.IsAnimated) { addWordToGifList(i, true); } else { g.FillRectangle(_selectionBrush, word.X + xOffset, word.Y + yOffset, word.Width + spaceWidth - 1, word.Height); } } } else { if (word.Type == SpanType.LazyLoadedImage) { var emote = (LazyLoadedImage)word.Value; if (emote.IsAnimated) { addWordToGifList(i, true); } } } } } else { for (int i = 0; i < message.Words.Count; i++) { var word = message.Words[i]; if (word.Type == SpanType.LazyLoadedImage) { var emote = (LazyLoadedImage)word.Value; if (emote.IsAnimated) { addWordToGifList(i, false); } } } } if (allowMessageSeperator && AppSettings.ChatSeperateMessages) { g.DrawLine(App.ColorScheme.ChatMessageSeperatorBorder, 0, yOffset + 1, message.Width + 128, yOffset + 1); g.DrawLine(App.ColorScheme.ChatMessageSeperatorBorderInner, 0, yOffset, message.Width + 128, yOffset); } if (message.HasAnyHighlightType(HighlightType.SearchResult)) { g.FillRectangle(Brushes.GreenYellow, 1, yOffset, 1, message.Height - 1); } }
private static void ReadConnection_MessageReceived(object sender, MessageEventArgs e) { var msg = e.Message; if (msg.Command == "PRIVMSG") { TwitchChannel.GetChannel(msg.Middle.TrimStart('#')).Process(c => { if (msg.PrefixUser == "twitchnotify") { c.AddMessage(new Message(msg.Params ?? "", HSLColor.Gray, true) { HighlightType = HighlightType.Resub }); } else { // check if ignore keyword is triggered if (AppSettings.IgnoredKeywordsRegex == null || !AppSettings.IgnoredKeywordsRegex.IsMatch(e.Message.Params)) { var message = new Message(msg, c); // check if user is on the ignore list if (AppSettings.EnableTwitchUserIgnores && IsIgnoredUser(message.Username)) { switch (AppSettings.ChatShowIgnoredUsersMessages) { case 1: if (!c.IsModOrBroadcaster) { return; } break; case 2: if (!c.IsBroadcaster) { return; } break; default: return; } } { c.Users[message.Username.ToUpper()] = message.DisplayName; if (message.HasAnyHighlightType(HighlightType.Highlighted)) { var mentionMessage = new Message(msg, c, enablePingSound: false, includeChannel: true) { HighlightType = HighlightType.None }; TwitchChannel.MentionsChannel.AddMessage(mentionMessage); } c.AddMessage(message); } } } }); } else if (msg.Command == "CLEARCHAT") { var channel = msg.Middle; var user = msg.Params; string reason; msg.Tags.TryGetValue("ban-reason", out reason); string _duration; var duration = 0; if (msg.Tags.TryGetValue("ban-duration", out _duration)) { int.TryParse(_duration, out duration); } TwitchChannel.GetChannel((msg.Middle ?? "").TrimStart('#')).Process(c => c.ClearChat(user, reason, duration)); //} } else if (msg.Command == "ROOMSTATE") { TwitchChannel.GetChannel((msg.Middle ?? "").TrimStart('#')).Process(c => { var state = c.RoomState; string value; if (msg.Tags.TryGetValue("emote-only", out value)) { if (value == "1") { state |= RoomState.EmoteOnly; } else { state &= ~RoomState.EmoteOnly; } } if (msg.Tags.TryGetValue("subs-only", out value)) { if (value == "1") { state |= RoomState.SubOnly; } else { state &= ~RoomState.SubOnly; } } if (msg.Tags.TryGetValue("slow", out value)) { if (value == "0") { state &= ~RoomState.SlowMode; } else { int time; if (!int.TryParse(value, out time)) { time = -1; } c.SlowModeTime = time; state |= RoomState.SlowMode; } } if (msg.Tags.TryGetValue("r9k", out value)) { if (value == "1") { state |= RoomState.R9k; } else { state &= ~RoomState.R9k; } } //if (e.Data.Tags.TryGetValue("broadcaster-lang", out value)) c.RoomState = state; }); } else if (msg.Command == "USERSTATE") { string value; if (msg.Tags.TryGetValue("mod", out value)) { TwitchChannel.GetChannel((msg.Middle ?? "").TrimStart('#')).Process(c => c.IsMod = value == "1"); } } else if (msg.Command == "WHISPER") { TwitchChannel.WhisperChannel.AddMessage(new Message(msg, TwitchChannel.WhisperChannel, true, false, isReceivedWhisper: true)); LastReceivedWhisperUser = msg.PrefixUser; if (AppSettings.ChatEnableInlineWhispers) { var inlineMessage = new Message(msg, TwitchChannel.WhisperChannel, true, false, true) { HighlightTab = false, HighlightType = HighlightType.Whisper }; foreach (var channel in TwitchChannel.Channels) { channel.AddMessage(inlineMessage); } } } else if (msg.Command == "USERNOTICE") { string sysMsg; msg.Tags.TryGetValue("system-msg", out sysMsg); TwitchChannel.GetChannel((msg.Middle ?? "").TrimStart('#')).Process(c => { try { var sysMessage = new Message(sysMsg, HSLColor.Gray, true) { HighlightType = HighlightType.Resub }; c.AddMessage(sysMessage); if (!string.IsNullOrEmpty(msg.Params)) { var message = new Message(msg, c) { HighlightType = HighlightType.Resub }; c.AddMessage(message); } } catch { } }); } }