예제 #1
0
        public static int DrawMessage(Graphics g, Message msg, Message prevMsg, Font fnt, ControlState state, int y = 0, int width = 500, int cHeight = 400, MouseState mouse = default(MouseState))
        {
            if (msg == null)
            {
                return(y);
            }

            int height = 0;

            const int padding = 10;

            const int avatarSz = 48;

            int hWidth   = width - avatarSz - 3 * padding;
            int msgWidth = width / 100 * 80;

            User usr = msg.Author;

            if (usr == null)
            {
                return(y);
            }

            Size hSize = Size.Empty;

            if (prevMsg == null || prevMsg.Author != usr)
            {
                int aX = padding;
                if (msg.Out)
                {
                    aX = width - padding - avatarSz;
                }

                Bitmap p = usr.GetPhoto();
                if (p != null && y > -avatarSz)
                {
                    g.DrawImage(p, new Rectangle(aX, y, avatarSz, avatarSz));
                }

                hSize = Size.Ceiling(g.MeasureString(usr.FullName, fnt, hWidth));

                int hX = 2 * padding + avatarSz;
                if (msg.Out)
                {
                    hX = width - 2 * padding - avatarSz - hSize.Width;
                }

                if (y > -hSize.Height)
                {
                    DrawString(g, usr.FullName, fnt, Brushes.DimGray, new Rectangle(new Point(hX, y), hSize));
                }
            }

            height += padding / 2 + hSize.Height;

            Size msgSize     = Size.Ceiling(g.MeasureString(msg.Body, fnt, msgWidth));
            Size msgRectSize = Size.Add(msgSize, new Size(2 * padding, 2 * padding));

            int rX = 2 * padding + avatarSz + 5;

            if (msg.Out)
            {
                rX = width - 2 * padding - avatarSz - msgRectSize.Width - 5;
            }

            int rY = y + padding / 2 + hSize.Height;

            if (msg.Attachments != null && msg.Attachments.Length > 0)
            {
                int ax = 0, ay = 0;
                int mw = 0, mh = 0;
                foreach (Attachment a in msg.Attachments)
                {
                    Size asz = a.Measure(g, fnt, msgWidth - ax, true);

                    if (mh < asz.Height)
                    {
                        mh = asz.Height;
                    }

                    if (ax + asz.Width > msgWidth)
                    {
                        ax  = 0;
                        ay += mh + padding;
                        mh  = 0;
                    }
                    else
                    {
                        ax += asz.Width + padding;
                    }

                    if (mw < ax)
                    {
                        mw = ax;
                    }
                }

                msgRectSize = new Size(Math.Max(msgSize.Width, mw) + padding, msgSize.Height + ay + mh + 2 * padding);

                rX = 2 * padding + avatarSz + 5;
                if (msg.Out)
                {
                    rX = width - 2 * padding - avatarSz - msgRectSize.Width - 5;
                }

                rY = y + padding / 2 + hSize.Height;
            }

            Color msgRectColor = Color.White;

            if (msg.Crypted)
            {
                msgRectColor = Color.Lime;
            }

            if (!msg.Read)
            {
                msgRectColor = Color.DodgerBlue;

                if (msg.Crypted)
                {
                    msgRectColor = Color.LimeGreen;
                }
            }

            Brush msgRectBrush = new SolidBrush(Color.FromArgb(128, msgRectColor));

            if (rY > -msgRectSize.Height && rY < cHeight)
            {
                g.FillRoundRectangle(msgRectBrush, new Rectangle(new Point(rX, rY), msgRectSize), padding / 2);
            }

            int tX = rX;
            int tY = rY + padding;

            if (msg.Out)
            {
                tX = rX + msgRectSize.Width;
            }

            g.FillPolygon(msgRectBrush, new[]
            {
                new Point(tX, tY),
                new Point(tX, tY + 16),
                new Point(((msg.Out) ? tX + 10 : tX - 10), tY + 8)
            });

            if (y + padding + padding / 2 + hSize.Height > -msgSize.Height && y < cHeight)
            {
                Rectangle msgRectangle = new Rectangle(new Point(rX + padding, y + padding + padding / 2 + hSize.Height), msgSize);

                /*if (msg.Body.Length > 256)
                 * {
                 *  DrawString(g, msg.Body, fnt, Brushes.Black, msgRectangle, StringAlignment.Near);
                 * }
                 * else
                 * {*/
                List <TextBlock> blocks;

                if (msg.RuntimeData.ContainsKey("TextBlocks"))
                {
                    blocks = (List <TextBlock>)msg.RuntimeData["TextBlocks"];
                }
                else
                {
                    blocks = new List <TextBlock>();

                    int blkend = 0;

                    MatchCollection matches = _URL.Matches(msg.Body);
                    if (matches.Count > 0)
                    {
                        foreach (Match m in matches)
                        {
                            String url = m.ToString();

                            int idx = msg.Body.IndexOf(url, StringComparison.Ordinal);

                            if (idx > blkend)
                            {
                                blocks.Add(new TextBlock(msg.Body, blkend, idx - blkend));
                            }

                            TextBlock blk = new TextBlock(msg.Body, idx, url.Length, TextStyle.Link);
                            blocks.Add(blk);

                            blkend = blk.End;
                        }
                    }

                    if (msg.Body.Length > blkend)
                    {
                        blocks.Add(new TextBlock(msg.Body, blkend, msg.Body.Length - blkend));
                    }

                    if (Emoji.FindEmojis(msg.Body).Count > 0)
                    {
                        List <TextBlock> nbl = new List <TextBlock>();

                        foreach (TextBlock b in blocks)
                        {
                            foreach (String em in Emoji.FindEmojis(b.Fragment))
                            {
                                int idx = b.Fragment.IndexOf(em, StringComparison.Ordinal);

                                if (idx > 0)
                                {
                                    nbl.Add(new TextBlock(msg.Body, b.Start, idx, b.Style, b.State));
                                }

                                nbl.Add(new EmojiBlock(msg.Body, b.Start + idx, em.Length, b.State));

                                if (idx + em.Length < b.Length)
                                {
                                    nbl.Add(new TextBlock(msg.Body, b.Start + idx + em.Length, b.Length - idx - em.Length, b.Style, b.State));
                                }
                            }
                        }

                        blocks = nbl;
                    }

                    Console.WriteLine(((msg.Body.Length > 32) ? msg.Body.Substring(0, 32) + "..." : msg.Body) + ": " + blocks.Count + " block(s)");

                    blocks.Sort((blk, blk2) => blk.Start.CompareTo(blk2.Start));

                    msg.RuntimeData.Add("TextBlocks", blocks);
                }

                if (blocks.Count > 16)
                {
                    DrawString(g, msg.Body, fnt, Brushes.Black, msgRectangle, StringAlignment.Near);
                }
                else
                {
                    int sX = rX + padding,
                        sY = y + padding + padding / 2 + hSize.Height,
                        eX = msgSize.Width,
                        eY = msgSize.Height;

                    int cX = 0, cY = 0, cH = 0;

                    CharacterRange[] ranges   = { new CharacterRange(0, 1) };
                    String           _c;
                    Rectangle        charRect = Rectangle.Empty;

                    int cP = 0;

                    using (StringFormat stringFormat = new StringFormat())
                    {
                        stringFormat.Alignment     = StringAlignment.Near;
                        stringFormat.LineAlignment = StringAlignment.Center;

                        foreach (TextBlock blk in blocks)
                        {
                            blk.StartPoint = new Point(cX, cY);

                            if (blk is EmojiBlock)
                            {
                                Bitmap e = ((EmojiBlock)blk).Emoji;

                                if (e != null)
                                {
                                    g.DrawImage(e, new Rectangle(new Point(sX + cX + 2, sY + cY), new Size(16, 16)));

                                    if (cH < 16)
                                    {
                                        cH = 16;
                                    }

                                    cX += 20;
                                    if (cX > eX)
                                    {
                                        cX  = 0;
                                        cY += cH;
                                    }
                                }

                                cP += blk.Length;
                            }
                            else
                            {
                                while (cP >= blk.Start && cP < blk.End)
                                {
                                    ranges[0].First = cP;

                                    stringFormat.SetMeasurableCharacterRanges(ranges);

                                    _c = msg.Body.Substring(cP, 1);

                                    charRect =
                                        Rectangle.Round(
                                            g.MeasureCharacterRanges(msg.Body, fnt, msgRectangle, stringFormat)[0]
                                            .GetBounds(g));

                                    if (cH < charRect.Height)
                                    {
                                        cH = charRect.Height;
                                    }

                                    Color c = Color.Black;
                                    if (blk.Style == TextStyle.Link)
                                    {
                                        c = Color.Blue;

                                        if (mouse != null)
                                        {
                                            int mpX = mouse.Position.X;
                                            int mpY = mouse.Position.Y;

                                            if (mpY >= sY + blk.StartPoint.Y && mpY <= sY + blk.EndPoint.Y &&
                                                mpX >= sX + blk.StartPoint.X &&
                                                mpX <= sX + blk.EndPoint.X)
                                            {
                                                blk.State = ControlState.Hover;

                                                if (mouse.Clicked)
                                                {
                                                    blk.State     = ControlState.Pressed;
                                                    mouse.Clicked = false;
                                                }
                                            }
                                            else
                                            {
                                                blk.State = ControlState.Idle;
                                            }

                                            if (blk.State != ControlState.Idle)
                                            {
                                                if (blk.State == ControlState.Hover)
                                                {
                                                    c = Color.DarkOrange;
                                                }

                                                if (blk.State == ControlState.Pressed)
                                                {
                                                    c = Color.Red;

                                                    App.Platform.OpenUrl(msg.Body.Substring(blk.Start, blk.Length));
                                                }

                                                g.FillRectangle(Brushes.White, charRect);
                                            }
                                        }
                                        else
                                        {
                                            blk.State = ControlState.Idle;
                                            c         = Color.Blue;
                                        }
                                    }

                                    g.DrawString(_c, fnt, new SolidBrush(c), sX + cX, sY + cY);

                                    if (blk.Style == TextStyle.Link)
                                    {
                                        g.DrawLine(new Pen(c), sX + cX + 2, sY + cY + cH, sX + cX + charRect.Width + 2,
                                                   sY + cY + cH);
                                    }

                                    cX += charRect.Width;
                                    if (cX > eX || _c == "\n")
                                    {
                                        cX  = 0;
                                        cY += cH;

                                        if (_c != "\n")
                                        {
                                            cH = 0;
                                        }
                                    }
                                    cP++;
                                }
                            }

                            blk.EndPoint = new Point(cX + charRect.Width + 2, cY + cH);
                        }
                    }
                }
            }

            height += msgRectSize.Height + padding;

            if (msg.Attachments != null && msg.Attachments.Length > 0)
            {
                int ax = 0, ay = 0;
                int mh = 0;
                foreach (Attachment a in msg.Attachments)
                {
                    Size asz = a.Measure(g, fnt, msgWidth - ax, true);

                    Rectangle aRect = new Rectangle(new Point(rX + padding + ax, rY + msgSize.Height + padding + ay), asz);

                    bool aHover = false, aClick = false;

                    if (mouse != null && aRect.Contains(mouse.Position))
                    {
                        aHover = true;

                        if (mouse.Clicked)
                        {
                            aClick        = true;
                            mouse.Clicked = false;
                        }
                    }

                    a.Draw(g, aRect, fnt, true, aHover, aClick);

                    if (mh < asz.Height)
                    {
                        mh = asz.Height;
                    }

                    if (ax + asz.Width > msgWidth)
                    {
                        ax  = 0;
                        ay += mh + padding;
                        mh  = 0;
                    }
                    else
                    {
                        ax += asz.Width + padding;
                    }
                }
            }

            return(height);
        }