internal void SetSelectionStartItem(Point p) { //清除其他的选择状态 this.Clear(); MessageListItem item = _owner.GetItemAtPosition(p) as MessageListItem; if (item == null) { return; } //设定文本选中 if (item.Message.Type == MessageType.Text) { this._selectingTextItem = item; Rectangle rect = item.Bounds; for (int i = 0; i < this._selectingTextItem.DrawingObjects.Count; i++) { DrawingObject dobj = item.DrawingObjects[i]; if (dobj.Type == DrawingObjectType.TextBlock) { Rectangle bounds = dobj.Offset(rect.X, rect.Y); if (bounds.Contains(p)) { TextBlockObj tb = dobj.Tag as TextBlockObj; StringPart sp = tb.StringPart; using (Graphics g = _owner.CreateGraphics()) { tb.SelectionStart = StringMeasurer.GetCharIndex(g, sp.Font, p.X - (int)dobj.X, sp.String); this._selectStartDoIndex = i; break; } } } } } }
public TextBlockObj(StringPart sp) { this.StringPart = sp; ClearSelection(); }
public static List <StringPart> Measure(Graphics g, Font font, int width, string str) { List <StringPart> spList = new List <StringPart>(16); int pos = 0; int x = 0, y = 0, w = 0, h = font.Height; string cutStr = ""; bool cFlag = false; bool cWrapFlag = false; for (int i = 0; i < str.Length;) { cWrapFlag = false; if (i == str.Length - 1) { w += GetCharWidth(str[i], g, font); cutStr = str.Substring(pos, i - pos + 1); cFlag = true; i++; } else if (str[i] == '\r') { cutStr = str.Substring(pos, i - pos); if (i + 1 < str.Length) { //\r\n i += 2; } else { i++; } cFlag = true; } else if (str[i] == '\n') { cutStr = str.Substring(pos, i - pos); i++; cFlag = true; } else { w += GetCharWidth(str[i], g, font); if (w > width) { cutStr = str.Substring(pos, i - pos); cFlag = true; cWrapFlag = true; } else { cFlag = false; } } if (cFlag) { StringPart sp = new StringPart { Bounds = new Rectangle(x, y, w, h), String = cutStr, TextFormatFlags = TextFormatFlags, Font = font, Wrap = cWrapFlag, }; spList.Add(sp); pos = i; y += h; w = 0; } else { i++; } } return(spList); }
protected override void OnDrawItem(UI.DrawItemEventArgs args) { MessageListItem item = args.Item as MessageListItem; Message m = item.Message; args.DrawBackground(); Graphics g = args.Graphics; g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; Rectangle rect = item.Bounds; Rectangle drawingObjRect; Point pos = PointToClient(MousePosition); foreach (DrawingObject dobj in item.DrawingObjects) { drawingObjRect = dobj.Offset(rect.X, rect.Y); switch (dobj.Type) { //头像 case DrawingObjectType.ProfilePhoto: { g.DrawImage(ProfilePhotoPool.GetPhoto(item.User.ID), drawingObjRect); if (drawingObjRect.Contains(pos)) { g.DrawRectangle(IMAGE_BORDER_PEN_FOCUS, drawingObjRect.X, drawingObjRect.Y, drawingObjRect.Width, drawingObjRect.Height); } break; } //时间, 昵称,状态 case DrawingObjectType.Title: { string text = item.User.NickName + " " + m.Time.ToString("yyyy/MM/dd HH:mm:ss"); if (!m.Flag) { text += " 传送失败"; } TextRenderer.DrawText(g, text, args.Font, new Point((int)drawingObjRect.X, (int)drawingObjRect.Y) , m.Flag ? SUCCESS_TITLE_COLOR : ERROR_TITLE_COLOR, TextFormatFlags.Left); break; } //文本消息 case DrawingObjectType.TextBlock: { TextBlockObj tb = dobj.Tag as TextBlockObj; StringPart sp = tb.StringPart; int selStart = Math.Min(tb.SelectionStart, tb.SelectionEnd); int selEnd = Math.Max(tb.SelectionStart, tb.SelectionEnd); string str1 = selStart == -1 ? sp.String : sp.String.Substring(0, selStart); string str2 = selStart == -1 ? "" : sp.String.Substring(selStart, tb.SelectionLength); string str3 = selEnd == -1 ? "" : sp.String.Substring(selEnd + 1); //选择前的文本 if (!string.IsNullOrEmpty(str1)) { TextRenderer.DrawText(g, str1, sp.Font, new Point((int)drawingObjRect.X, (int)drawingObjRect.Y), args.ForeColor, StringMeasurer.TextFormatFlags); } //选择中文本 if (!string.IsNullOrEmpty(str2)) { int w1 = StringMeasurer.Width(g, sp.Font, str1, sp.TextFormatFlags); int w2 = StringMeasurer.Width(g, sp.Font, str2, sp.TextFormatFlags); drawingObjRect.X += w1; drawingObjRect.Width = w2; g.FillRectangle(BrushPool.GetBrush(TEXT_SELECTION_BACK_COLOR), drawingObjRect); TextRenderer.DrawText(g, str2, sp.Font, new Point((int)drawingObjRect.X, (int)drawingObjRect.Y), TEXT_SELECTION_FORE_COLOR, StringMeasurer.TextFormatFlags); //选择后的文本 if (!string.IsNullOrEmpty(str3)) { drawingObjRect.X += w2; drawingObjRect.Width = dobj.Width - w1 - w2; TextRenderer.DrawText(g, str3, sp.Font, new Point((int)drawingObjRect.X, (int)drawingObjRect.Y), args.ForeColor, StringMeasurer.TextFormatFlags); } } break; } case DrawingObjectType.Image: { Image image = (m as ImageMessage).Image; g.DrawImage(image, drawingObjRect); if (drawingObjRect.Contains(pos)) { g.DrawRectangle(IMAGE_BORDER_PEN_FOCUS, drawingObjRect.X, drawingObjRect.Y, drawingObjRect.Width, drawingObjRect.Height); } else { g.DrawRectangle(IMAGE_BORDER_PEN, drawingObjRect.X, drawingObjRect.Y, drawingObjRect.Width, drawingObjRect.Height); } break; } case DrawingObjectType.File: { FileMessage fm = m as FileMessage; //底背景 g.FillRectangle(Brushes.White, drawingObjRect); if (drawingObjRect.Contains(pos)) { g.DrawRectangle(IMAGE_BORDER_PEN_FOCUS, drawingObjRect.X, drawingObjRect.Y, drawingObjRect.Width, drawingObjRect.Height); } else { g.DrawRectangle(IMAGE_BORDER_PEN, drawingObjRect.X, drawingObjRect.Y, drawingObjRect.Width, drawingObjRect.Height); } //文件名,文件大小,ICON Image image = FileIconPool.GetIcon(fm.OriginFilePath); int imageWidth = 64; int imageHeight = 64 * image.Height / image.Width; Rectangle imageRect = new Rectangle(drawingObjRect.X + FILE_SEND_WIDTH - imageWidth - MARGIN, drawingObjRect.Y + MARGIN, imageWidth, FILE_SEND_HEIGHT - Font.Height - MARGIN * 3); Rectangle fileNameRect = new Rectangle(drawingObjRect.X + MARGIN, drawingObjRect.Y + MARGIN, FILE_SEND_WIDTH - imageWidth - MARGIN * 3, FILE_SEND_HEIGHT - Font.Height - MARGIN * 3); Rectangle fontRect = new Rectangle(drawingObjRect.X + MARGIN, drawingObjRect.Y + FILE_SEND_HEIGHT - Font.Height - MARGIN, FILE_SEND_WIDTH - MARGIN * 2, Font.Height); Rectangle pieRect = new Rectangle(drawingObjRect.X + (FILE_SEND_WIDTH - PROGRESS_PIE_D) / 2, drawingObjRect.Y + (FILE_SEND_HEIGHT - PROGRESS_PIE_D) / 2, PROGRESS_PIE_D, PROGRESS_PIE_D); Rectangle processRect = new Rectangle(drawingObjRect.X, drawingObjRect.Y + (FILE_SEND_HEIGHT - Font.Height * 2) / 2, FILE_SEND_WIDTH, Font.Height * 2); //当文件名超过显示部分时,中间用省略号表示 string str = fm.FileName; SizeF s = g.MeasureString(fm.FileName, Font, new System.Drawing.SizeF((float)fileNameRect.Width, (float)fileNameRect.Height), StringFormat.GenericDefault, out int count, out int lines); if (s.Height >= fileNameRect.Height & str.Length >= count) { //由于会出现半行的情况,直接写死了所取的字符串数目 str = str.Substring(0, 36) + "・・・" + str.Substring(str.Length - 4); } g.DrawImage(image, imageRect.X, imageRect.Y, imageWidth, imageHeight); g.DrawString(str, args.Font, Brushes.Black, fileNameRect); TextRenderer.DrawText(g, LanFile.HumanReadbleLen(fm.FileLength), args.Font, fontRect, Color.FromArgb(0, 0, 0), TextFormatFlags.Left); if (item.State == MessageState.Receiving || item.State == MessageState.Sending) { //接受进度 g.FillRectangle(MESSAGELIST_PROGRESS_BACKGROUND_BRUSH, drawingObjRect); g.DrawPie(PROGRESS_PEN, pieRect, 0, 360); g.FillPie(MESSAGELIST_PROGRESS_FILLED_BRUSH, pieRect, 0, 360 * item.Progress / 100); //TODO 显示剩余时间,传输速度 TextRenderer.DrawText(g, item.Progress + "%" + "\r\n" + LanFile.HumanReadbleLen(item.FileTransportedLength) + "/" + LanFile.HumanReadbleLen(fm.FileLength), args.Font, processRect, Color.FromArgb(0, 0, 0), TextFormatFlags.HorizontalCenter); } break; } } } }
internal void SetSelectionEndItem(Point location) { if (!this.HasSelection) { return; } MessageListItem hoverItem = _owner.GetItemAtPosition(location) as MessageListItem; if (hoverItem == null) { //鼠标移动到其他地方了,算了,不选了 this.Clear(); return; } if (hoverItem != this._selectingTextItem) { //当前的选择的不是上面一个 this.Clear(); return; } Rectangle rect = this._selectingTextItem.Bounds; for (int i = 0; i < this._selectingTextItem.DrawingObjects.Count; i++) { DrawingObject dobj = this._selectingTextItem.DrawingObjects[i]; if (dobj.Type == DrawingObjectType.TextBlock) { Rectangle bounds = dobj.Offset(rect.X, rect.Y); TextBlockObj tb = dobj.Tag as TextBlockObj; if (bounds.Contains(location)) { StringPart sp = tb.StringPart; using (Graphics g = _owner.CreateGraphics()) { tb.SelectionEnd = StringMeasurer.GetCharIndex(g, sp.Font, location.X - (int)dobj.X, sp.String); this._selectEndDoIndex = i; break; } } } } //开始与结束直接的所有TextBlock都设定为全选中 int startIndex = Math.Min(this._selectStartDoIndex, this._selectEndDoIndex); int endIndex = Math.Max(this._selectStartDoIndex, this._selectEndDoIndex); List <TextBlockObj> selObj = new List <TextBlockObj>(); for (int i = startIndex; i <= endIndex; i++) { DrawingObject dobj = this._selectingTextItem.DrawingObjects[i]; if (dobj.Type == DrawingObjectType.TextBlock) { TextBlockObj tbObj = dobj.Tag as TextBlockObj; if (this._selectStartDoIndex < this._selectEndDoIndex) { //从上往下选择时 if (i == this._selectStartDoIndex) { tbObj.SelectionEnd = tbObj.Length - 1; } else if (i == this._selectEndDoIndex) { tbObj.SelectionStart = 0; } } else if (this._selectStartDoIndex > this._selectEndDoIndex) { //从下往上选择时 if (i == this._selectStartDoIndex) { tbObj.SelectionEnd = 0; } else if (i == this._selectEndDoIndex) { tbObj.SelectionStart = tbObj.Length - 1; } } if (i != this._selectStartDoIndex && i != this._selectEndDoIndex) { tbObj.SelectAll(); } selObj.Add(tbObj); this._prevSelection.Remove(tbObj); } } //清除选择 foreach (TextBlockObj item in this._prevSelection) { item.ClearSelection(); } this._prevSelection = selObj; }