using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Drawing2D; using System.Linq; using System.Text; using System.Windows.Forms; namespace CMSControl { public enum eSystemStep : byte { IDLE = 0, INPUT, OUTPUT, REINPUT, FINISH, RESULT, CLOSING = 90, CLOSEWAIT, CLOSED, } public partial class cmsview : Control { public eSystemStep step = eSystemStep.IDLE; public UInt16 _page; private Point _gridcount; public UInt16 GridItemCount { get { return (UInt16)(_gridcount.X * _gridcount.Y); } } public Boolean isDebug { get; set; } public int LastContactSlotIDX = -1; //private Font _fontid; //private Font _fontno; //private Font _fontcontent; public float NoStrSize = 100f; public Boolean bRePaint; public List Slots = new List(); public List Items = new List(); public UInt16 ItemMargin { get; set; } public Point GridCount { get { return _gridcount; } set { _gridcount = value; } } public Font Font_No; //slotno public Font Font_Top; //top public Font Font_Bottom; //bottom public Font Font_Middle; //bottom public Font Font_Count; //bottom public System.Drawing.Color color_font_no = Color.White; public System.Drawing.Color color_font_top = Color.White; public System.Drawing.Color color_font_middle = Color.White; public System.Drawing.Color color_font_bottom_left = Color.White; public System.Drawing.Color color_font_bottom_right = Color.White; public Padding Padding_No; public Padding Padding_Top; public Padding Padding_Bottom; public Padding Padding_Middle; public Padding Padding_Count; public string DisplayT; public string DisplayM; public string DisplayBL; public string DisplayBR; public System.Windows.Forms.HorizontalAlignment TextAlignT = HorizontalAlignment.Left; public System.Windows.Forms.HorizontalAlignment TextAlignM = HorizontalAlignment.Left; public System.Windows.Forms.HorizontalAlignment TextAlignBL = HorizontalAlignment.Left; public System.Windows.Forms.HorizontalAlignment TextAlignBR = HorizontalAlignment.Right; public Boolean Enable_MultiBox = false; public event EventHandler ItemClick; public event EventHandler Message; public UInt16 GetMaxPageCount { get { if (GridItemCount == 0) return 0; return (UInt16)(Math.Ceiling(Slots.Count * 1.0 / GridItemCount)); } } public UInt16 Page { get { return _page; } set { if (value < 1) value = 1; UInt16 MaxPage = GetMaxPageCount; if (MaxPage < 1) MaxPage = 1; if (value > MaxPage) value = MaxPage; if (value != _page) { _page = value; bRePaint = true; this.Invalidate(); } } } public cmsview() { this.SetStyle(ControlStyles.UserPaint, true); this.SetStyle(ControlStyles.AllPaintingInWmPaint, true); this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); this.SetStyle(ControlStyles.SupportsTransparentBackColor, true); // Redraw when resized this.SetStyle(ControlStyles.ResizeRedraw, true); this.Resize += arLabel_Resize; this.MouseDown += cmsview_MouseDown; this._page = 1; ItemMargin = 3; this.GridCount = new Point(8, 12); Font_No = new Font("Consolas", 15f); Font_Bottom = new Font("Consolas", 8f); Font_Top = new Font("Consolas", 8f); bRePaint = false; isDebug = false; } public void RaiseMessage(Boolean iserr, string msg) { if (Message != null) Message(this, new MessageEvent(iserr, msg)); } public void ClearSelectItem() { foreach (var no in preSelectedIndex) this.Slots[no].Selected = false; } /// /// 지정한 index 의 아이템을 선택합니다. 페이지는 자동 전환됩니다. /// /// public Boolean SelectItem(int idx) { ushort newPage = (ushort)(Math.Ceiling((double)(idx + 1) / GridItemCount)); if (newPage != this._page) Page = newPage; if (idx >= Slots.Count) { RaiseMessage(true, "Index (" + idx.ToString() + ")Range Error ItemCount=" + this.Slots.Count.ToString()); return false; //존재하지않는 아이템이다. } Slots[idx].Selected = true; if (ItemClick != null) ItemClick(this, new ItemClickEvent(Point.Empty, idx, MouseButtons.Left, eClickArea.No)); //이전에 선택된 것은 제거한다. ClearPreSelected(); preSelectedIndex.Add(idx); this.Invalidate(); return true; } /// /// id가 일치하는 대상을 모두 찾습니다. /// /// public int SelectItem(string ID1, string ID2) { int retval = 0; //이전에 선택된 것은 제거한다. ClearPreSelected(); //자식데이터가 속해있다면 그것들을 모두 체크해야한다. var items = this.Items.Where(t => t.ID1 == ID1 && t.ID2 == ID2); if (items.Count() < 1) { RaiseMessage(false, "Not Found UID=" + ID1); return retval; } //해당 자식들이 속해잇는 슬롯을 모두 선택해준다. foreach (var item in items) { if (item.SlotIDX < this.Slots.Count) { var slot = this.Slots[item.SlotIDX]; if (!slot.Selected) { slot.Selected = true; retval += 1; preSelectedIndex.Add(slot.Index); } } } ushort newPage = 1; if (preSelectedIndex.Count > 0) newPage = (ushort)(Math.Ceiling((double)(preSelectedIndex[preSelectedIndex.Count - 1] + 1) / GridItemCount)); if (newPage != this._page) Page = newPage; if (ItemClick != null && preSelectedIndex.Count > 0) ItemClick(this, new ItemClickEvent(Point.Empty, preSelectedIndex[0], MouseButtons.Left, eClickArea.No)); this.Invalidate(); return retval; } public int SelectItem(string ID1) { int retval = 0; //이전에 선택된 것은 제거한다. ClearPreSelected(); //자식데이터가 속해있다면 그것들을 모두 체크해야한다. var items = this.Items.Where(t => t.ID1 == ID1); if (items.Count() < 1) { RaiseMessage(false, "Not Found UID=" + ID1); return 0; } //해당 자식들이 속해잇는 슬롯을 모두 선택해준다. foreach (var item in items) { if (item.SlotIDX < this.Slots.Count) { var slot = this.Slots[item.SlotIDX]; if (!slot.Selected) { slot.Selected = true; retval += 1; preSelectedIndex.Add(slot.Index); } } } ushort newPage = 1; if (preSelectedIndex.Count > 0) newPage = (ushort)(Math.Ceiling((double)(preSelectedIndex[preSelectedIndex.Count - 1] + 1) / GridItemCount)); if (newPage != this._page) Page = newPage; this.Invalidate(); return retval; } public List preSelectedIndex = new List(); void cmsview_MouseDown(object sender, MouseEventArgs e) { //클릭을 하면 어떤개체가 if (GridItemCount < 1 || Slots.Count < 1) { RaiseMessage(true, "No items"); return; } int StartIndex = (this.Page - 1) * GridItemCount; for (int i = StartIndex; i < (StartIndex + GridItemCount); i++) { if (i < Slots.Count) { var item = Slots[i]; if (item.Rect.Contains(e.Location)) { eClickArea area = eClickArea.Normal; if (item.RectNo.Contains(e.Location)) area = eClickArea.No; else if (item.RectM.Contains(e.Location)) area = eClickArea.Title; else if (item.RectB.Contains(e.Location)) area = eClickArea.Content; item.Selected = true; if (ItemClick != null) ItemClick(this, new ItemClickEvent(e.Location, item.Index, e.Button, area)); ClearPreSelected(); preSelectedIndex.Add(item.Index); item.Selected = true; this.Invalidate(); break; } } else break; } } void ClearPreSelected() { //이전에 선택된 것은 제거한다. foreach (var index in preSelectedIndex) if (index < Slots.Count) Slots[index].Selected = false; preSelectedIndex.Clear(); } void arLabel_Resize(object sender, EventArgs e) { bRePaint = true; Invalidate(); } int cnt = 0; protected override void OnPaint(PaintEventArgs pe) { base.OnPaint(pe); cnt += 1; int StartIndex = (this.Page - 1) * GridItemCount; if (GridItemCount < 1) { DrawHelp(pe.Graphics); } else { ///테스트로 데이터를 만든다. if (Slots.Count < 1) { for(int i = 0; i < this.GridItemCount;i++) { Slots.Add(new Slot() { BackColor = Color.Lime, BorderColor = Color.Gray, BorderSize = 2f, Enable = true, ForeColor = Color.Black, Name = "test" + i.ToString(), Index = (byte)i, No = (i+1).ToString(), Selected = false }); } bRePaint = true; } //영역을 다시그려야하는 상황 if (bRePaint && GridItemCount > 0 && Slots.Count > 0) { int gridW = (int)((this.Width - this.Padding.Left - this.Padding.Right) / GridCount.X); int gridH = (int)((this.Height - this.Padding.Top - this.Padding.Bottom) / GridCount.Y); Rectangle rect, rect2, rectNo, rectT, rectM, rectB, rectCNT; int idx = 0; for (int r = 0; r < GridCount.Y; r++) { for (int c = 0; c < GridCount.X; c++) { int x = (c * gridW); int y = (r * gridH); rect = new Rectangle(x + this.Padding.Left, y + this.Padding.Top, gridW, gridH); rect2 = new Rectangle( rect.Left + this.ItemMargin, rect.Top + ItemMargin, rect.Width - ItemMargin * 2, rect.Height - ItemMargin * 2); float NoWidth = NoStrSize; // rect2.Width * 0.2f; rectNo = new Rectangle(rect2.Left, rect2.Top, (int)NoWidth, (int)(rect2.Height * 0.3)); var dispHeight1 = (int)(rect2.Height * 0.3); var dispHeight2 = (int)(rect2.Height * 0.4); var dispHeight3 = rect2.Height - dispHeight1 - dispHeight2; rectT = new Rectangle(rectNo.Right, rect2.Top, rect2.Width - rectNo.Width, dispHeight1); ; rectM = new Rectangle(rectNo.Left, rectT.Bottom, rect2.Width, dispHeight2); rectB = new Rectangle(rectNo.Left, rectM.Bottom, (int)(rect2.Width / 2.0), dispHeight3); rectCNT = new Rectangle(rectB.Right, rectM.Bottom, (int)(rect2.Width / 2.0), dispHeight3); if (StartIndex + idx < Slots.Count) { //items[StartIndex + idx].No = (byte)( idx + 1); Slots[StartIndex + idx].Rect = rect2; Slots[StartIndex + idx].RectNo = rectNo; Slots[StartIndex + idx].RectT = rectT; Slots[StartIndex + idx].RectM = rectM; Slots[StartIndex + idx].RectB = rectB; Slots[StartIndex + idx].RectCnt = rectCNT; Slots[StartIndex + idx].ForeColor = this.ForeColor; idx += 1; } else break; } if (StartIndex + idx >= Slots.Count) break; } bRePaint = false; } for (int i = StartIndex; i < StartIndex + GridItemCount; i++) { if (i >= Slots.Count) break; //over check var item = Slots[i]; var slotItems = Items.Where(t => t.SlotIDX == item.Index); DrawSlot(pe.Graphics, item, slotItems); } if (isDebug) { using (Font f = new Font("Consolas", 15)) { System.Text.StringBuilder sb = new StringBuilder(); sb.AppendLine("## Debug Message ##"); sb.AppendLine("Step : " + this.step.ToString()); sb.AppendLine("Refresh Count : " + this.cnt.ToString()); sb.AppendLine("Slot count : " + Slots.Count.ToString()); sb.AppendLine("Item Count : " + Items.Count.ToString()); sb.AppendLine("font no : " + this.Font_No.ToString()); sb.AppendLine("font top : " + this.Font_Top.ToString()); sb.AppendLine("font mid : " + this.Font.ToString()); sb.AppendLine("font bot : " + this.Font_Bottom.ToString()); sb.Append("Pre Selected index : "); foreach (var item in preSelectedIndex) sb.Append(item + ","); if (preSelectedIndex.Count == 1) { //세부내역도 표시한다. var slot = this.Slots[preSelectedIndex[0]]; var items = this.Items.Where(t => t.SlotIDX == slot.Index); foreach (var item in items) { sb.Append("item " + item.ID1 + ",qty=" + item.Qty.ToString()); } } pe.Graphics.DrawString(sb.ToString(), f, Brushes.Black, 11f, 11f); pe.Graphics.DrawString(sb.ToString(), f, Brushes.Yellow, 10f, 10f); } } } } void DrawHelp(Graphics g) { System.Text.StringBuilder sb = new StringBuilder(); sb.AppendLine("컨트롤 설정이 완료되지 않았습니다.\n"); sb.AppendLine("이 메세지는 GRID COUNT가 설정되지 않았거나 ITEMS 항목이 없는 경우 표시됩니다."); sb.AppendLine("ITEMS 갯수가 GRID 갯수를 넘을 경우 페이지가 분리됩니다.\n"); sb.AppendLine("현재 GRID 갯수는 : " + GridCount.ToString() + " = " + GridItemCount.ToString() + " 입니다."); sb.AppendLine("현재 ITEM 갯수는 : " + Slots.Count.ToString() + " 입니다.\n"); sb.AppendLine("화면에 5x10 의 배열로 표시를 하려면 GridCount에 5x10을 설정하세요."); sb.AppendLine("ITEMS 는 코드상에서 입력하세요.\n"); sb.AppendLine("# Example #"); sb.AppendLine("var newitem = new CMSControl.Item();"); sb.AppendLine("newitem.No = \"--\";"); sb.AppendLine("newitem.Title = \"ItemName\""); sb.AppendLine("newitem.Contents = \"Model No\";"); sb.AppendLine("cmsview1.items.Add(newitem);"); g.DrawString(sb.ToString(), this.Font, Brushes.Red, 10f, 10f); } public Color slotColorUnUsed = Color.DimGray; public Color slotColorDisable = Color.Gray; public Color slotColorSelect = Color.Lime; void DrawSlot(Graphics g, Slot slot, IEnumerable items) { if (slot.Rect.IsEmpty) return; //fill background color g.FillRectangle(Brushes.Gray, slot.Rect); Color bdColor = Color.FromArgb(194, 192, 194); Color bColor = slot.BackColor; float bSize = 1.0f; if (slot.Selected) { bSize = 5.5f; //bColor = slotColorSelect; bdColor = Color.Lime; } else if (slot.Index == LastContactSlotIDX) { bdColor = Color.Yellow; bSize = 5.5f; } if (!slot.Enable) bColor = slotColorDisable; else if (items.Count() < 1) bColor = slotColorUnUsed; //no Color.FromArgb(231, 229, 231) byte R = bColor.R; byte G = bColor.G; byte B = bColor.B; if (R > 22) R -= 22; else R = 0; if (G > 22) G -= 22; else G = 0; if (B > 22) B -= 22; else B = 0; Color bgColor2 = Color.FromArgb(R, G, B); using (LinearGradientBrush brush = new LinearGradientBrush(slot.RectNo, bColor, bgColor2, LinearGradientMode.Vertical)) { g.FillRectangle(brush, slot.RectNo); } g.DrawRectangle(new Pen(bColor), slot.RectNo); if (slot.Opend) { if (slot.BorderColor == Color.Yellow) bdColor = Color.Tomato; else bdColor = Color.Yellow; bSize = 5.0f; } Boolean ItemQtyManage = true; Boolean ItemQtySummary = false; Boolean ItemExpManage = false; if (items.Count() > 0) { var itemInfo = items.First(); ItemQtyManage = itemInfo.QtyManage; ItemQtySummary = itemInfo.QtySummary; ItemExpManage = itemInfo.ExpManage; } //아이템이 여러개 있다면 우측 상단에 책갈피 처럼 표시한다. if (items.Count() > 1) { Rectangle openrect = new Rectangle( (int)(slot.Rect.Right - 15), (int)(slot.Rect.Top + 1), 15, 15); Point[] pts = new Point[4]; pts[0] = new Point(slot.Rect.Right - 30, slot.Rect.Top + 1); pts[1] = new Point(slot.Rect.Right - 1, slot.Rect.Top + 1); pts[2] = new Point(slot.Rect.Right - 1, slot.Rect.Top + 30); pts[3] = new Point(slot.Rect.Right - 30, slot.Rect.Top + 1); g.FillPolygon(new SolidBrush(Color.FromArgb(40, 40, 40)), pts); using (Font f = new Font("맑은 고딕", 10f)) DrawString(g, f, items.Count().ToString(), openrect, Color.White, 0); } string slotnoStr = (slot.Index + 1).ToString(); if (slot.No != "") slotnoStr = slot.No; //180607 if (slot.Enable) { string StrT = slot.Name; string StrM = string.Empty; string StrBL = string.Empty; string StrBR = string.Empty; //값이없는 경우 세부항목에서 가져온다. var subItems = items.ToArray(); if (StrT == "") { StrT = ParserMessage(DisplayT, subItems); // subItems[0].ID1 + "\n" + subItems[0].VNAME; } if (subItems.Count() > 0) { StrM = ParserMessage(DisplayM, subItems);// subItems[0].Name; StrBL = ParserMessage(DisplayBL, subItems);// subItems[0].Model; StrBR = ParserMessage(DisplayBR, subItems);// "[" + subItems[0].Qty.ToString() + subItems[0].Unit + "]"; } //g.DrawRectangle(new Pen(Color.Magenta, 1.5f), RectT); //g.DrawRectangle(new Pen(Color.Red, 1.5f), RectM); //g.DrawRectangle(new Pen(Color.Yellow, 1.5f), RectB); //g.DrawRectangle(new Pen(Color.Yellow, 1.5f),); DrawString(g, Font_No, slotnoStr, slot.RectNo, color_font_no, HorizontalAlignment.Center, Padding_No); //title if (StrT != "") DrawString(g, Font_Top, StrT, slot.RectT, color_font_top, TextAlignT, Padding_Top); if (StrM != "") DrawString(g, Font_Middle, StrM, slot.RectM, color_font_middle, TextAlignM, Padding_Middle); if (StrBL != "") DrawString(g, Font_Bottom, StrBL, slot.RectB, color_font_bottom_left, TextAlignBL, Padding_Bottom); if (StrBR != "" && ItemQtyManage) DrawString(g, Font_Count, StrBR, slot.RectCnt, color_font_bottom_right, TextAlignBR, Padding_Count); } else { DrawString(g, this.Font_No, slotnoStr, slot.RectNo, color_font_no); DrawString(g, this.Font_Middle, "Disabled", slot.RectM, color_font_no); //DrawString(g, fConttent, "DISABLED", RectT, Color.Black, 0); } //g.DrawRectangle(Pens.White, slot.RectT); //g.DrawRectangle(Pens.White, slot.RectM); //g.DrawRectangle(Pens.White, slot.RectB); //g.DrawRectangle(Pens.White, slot.RectCnt); //g.DrawString(items.Count().ToString(), fNo, Brushes.Red, Rect.Left, Rect.Top); g.DrawLine(new Pen(Color.Black, 5f), slot.Rect.Left + 3, slot.Rect.Bottom + 1, slot.Rect.Right + 2, slot.Rect.Bottom + 1); g.DrawLine(new Pen(Color.Black, 5f), slot.Rect.Right + 1, slot.Rect.Top + 3, slot.Rect.Right + 1, slot.Rect.Bottom + 4); //g.DrawRectangle(Pens.Black, slot.Rect.Left + 1, slot.Rect.Top + 1, slot.Rect.Width - 2, slot.Rect.Height - 2); using (Pen p = new Pen(bdColor, bSize)) { g.DrawRectangle(p, slot.Rect); //최종테두리 } slot.BorderColor = bdColor; //g.DrawString(this.BackColor.ToString(), fID, Brushes.Black,RectNo.Left, RectNo.Top); if (slot.Expiration) { string msg = "Expiration"; var fsize = g.MeasureString(msg, this.Font); var rectheight = (int)(fsize.Height * 1.5); Rectangle msgRect = new Rectangle(slot.Rect.Left + 1, slot.Rect.Bottom - rectheight, slot.Rect.Width - 1, rectheight); g.FillRectangle(new SolidBrush(Color.FromArgb(100, Color.Red)), msgRect); DrawString(g, this.Font, msg, msgRect, Color.White); //g.DrawString("expiration", this.Font, Brushes.White, msgRect.Left, msgRect.Top); } } string ParserMessage(string org, Item[] subItems) { org = org.Replace("\\n", "\n"); if (subItems.Length > 0) { var item = subItems[0]; org = org.Replace("{ID1}", item.ID1); org = org.Replace("{ID2}", item.ID2); org = org.Replace("{NAME}", item.Name); org = org.Replace("{MODEL}", item.Model); org = org.Replace("{SERIAL}", item.Serial); if (item.ScaleUnit != item.Unit && item.ScaleUnit != "") { org = org.Replace("{QTY}", (item.Qty / item.Scale).ToString()); org = org.Replace("{UNIT}", item.ScaleUnit); } else { org = org.Replace("{QTY}", item.Qty.ToString()); org = org.Replace("{UNIT}", item.Unit); } } else { org = org.Replace("{ID1}", string.Empty); org = org.Replace("{ID2}", string.Empty); org = org.Replace("{NAME}", string.Empty); org = org.Replace("{MODEL}", string.Empty); org = org.Replace("{SERIAL}", string.Empty); org = org.Replace("{QTY}", string.Empty); org = org.Replace("{UNIT}", string.Empty); } return org; } void DrawString(Graphics g, Font f, string data, Rectangle rect, Color fcolor, System.Windows.Forms.HorizontalAlignment align = HorizontalAlignment.Center, Padding pad = new Padding()) { var fsize = g.MeasureString(data, f); float cx, cy; cx = cy = 0; switch (align) { case HorizontalAlignment.Left: cx = pad.Left + rect.Left; cy = pad.Top + rect.Top + (rect.Height - fsize.Height) / 2.0f; break; case HorizontalAlignment.Center: cx = pad.Left + rect.Left + (rect.Width - fsize.Width) / 2.0f; cy = pad.Top + rect.Top + (rect.Height - fsize.Height) / 2.0f; break; case HorizontalAlignment.Right: cx = rect.Right - fsize.Width - pad.Right; cy = pad.Top + rect.Top + (rect.Height - fsize.Height) / 2.0f; break; } g.DrawString(data, f, new SolidBrush(fcolor), new PointF(cx + 1, cy + 1)); } } }