Files
2025-07-17 16:11:46 +09:00

633 lines
24 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace arFrame.Control
{
public partial class GridView : System.Windows.Forms.Control
{
private int bordersize = 0;
private int menubordersize = 1;
private int menugap = 5;
private System.Windows.Forms.Padding padding = new Padding(3, 3, 3, 3);
private System.Drawing.Color backcolor = System.Drawing.Color.White;
private System.Drawing.Color bordercolor = System.Drawing.Color.Black;
private Boolean textattachtoimage = true;
private Boolean _showIndexString = true;
private System.Drawing.Color _shadowColor = System.Drawing.Color.Transparent;
private System.Drawing.Color foreColorPin = System.Drawing.Color.WhiteSmoke;
private System.Drawing.Font fontPin = new Font("Consolas", 8, FontStyle.Bold);
private Point _matrixsize = new Point(8, 2);
public Point MatrixSize { get { return _matrixsize; } set { _matrixsize = value; ResetArray(); RemakeChartRect(); } }
public Boolean arVeriticalDraw { get; set; }
[Browsable(false)]
public int ColumnCount { get { return _matrixsize.X; } }
[Browsable(false)]
public int RowCount { get { return _matrixsize.Y; } }
public int ItemCount { get { return ColumnCount * RowCount; } }
private GridViewItem[] Items;
private UInt16[] _values;
private string[] _titles;
private string[] _tags;
private string[] _names;
private ColorListItem[] _colorlist;
public ColorListItem[] ColorList { get { return _colorlist; } set { _colorlist = value; this.Invalidate(); } }
public string[] Names { get { return _names; } set { _names = value; Invalidate(); } }
public string[] Titles { get { return _titles; } set { _titles = value; Invalidate(); } }
public UInt16[] Values { get { return _values; } set { _values = value; Invalidate(); } }
public string[] Tags { get { return _tags; } set { _tags = value; } }
private bool _showdebuginfo = false;
public Boolean showDebugInfo { get { return _showdebuginfo; } set { _showdebuginfo = value; Invalidate(); } }
public void setNames(string[] value)
{
_names = value;
}
public void setTitle(string[] value)
{
List<string> titlerows = new List<string>();
List<string> tagrows = new List<string>();
for (int i = 0; i < value.Length; i++)
{
var r = (int)(Math.Floor((double)(i / ColumnCount)));
var c = i % ColumnCount;
//세로 그리기 였을때에는 다르게 처리해야함 201215
if(arVeriticalDraw)
{
c = (int)(Math.Floor((double)(i / ColumnCount)));
r = i % ColumnCount;
}
if (titlerows.Count < r + 1) titlerows.Add(string.Empty);
if (tagrows.Count < r + 1) tagrows.Add(string.Empty);
var prestr = titlerows[r];
if (c > 0 ) prestr += "|";
titlerows[r] = prestr + value[i];
var prestr_t = tagrows[r];
if (prestr_t != "") prestr_t += "|";
tagrows[r] = prestr_t + "";
if (i < itemCount) this.Items[i].Enable = true;
}
this._titles = titlerows.ToArray();
this._tags = tagrows.ToArray();
}
public void setTags(string[] value)
{
List<string> titlerows = new List<string>();
for (int i = 0; i < value.Length; i++)
{
var r = (int)(Math.Floor((double)(i / ColumnCount)));
var c = i % ColumnCount;
if (titlerows.Count < r + 1) titlerows.Add(string.Empty);
var prestr = titlerows[r];
if (c > 0 ) prestr += "|";
titlerows[r] = prestr + value[i];
if (i < itemCount) this.Items[i].Enable = true;
}
this._tags = titlerows.ToArray();
}
public Boolean setTitle(int row, int col, string value, string itemtag = "")
{
if (_titles == null) _titles = new string[0];
if (_tags == null) _tags = new string[0];
if (row >= _titles.Length) Array.Resize(ref _titles, row + 1);
if (row >= _tags.Length) Array.Resize(ref _tags, row + 1);
if (_titles[row] == null) _titles[row] = string.Empty;
if (_tags[row] == null) _tags[row] = string.Empty;
var linebuf = _titles[row].Split('|');
var linebuf_t = _tags[row].Split('|');
if (col >= linebuf.Length) Array.Resize(ref linebuf, col + 1);
if (col >= linebuf_t.Length) Array.Resize(ref linebuf_t, col + 1);
linebuf[col] = value;
linebuf_t[col] = itemtag;
_titles[row] = string.Join("|", linebuf);
_tags[row] = string.Join("|", linebuf_t);
return true;
//var idx = row * this.ColumnCount + col;
//return setTitle(idx, value);
}
public Boolean setTitle(int idx, string value)
{
if (idx < ColumnCount) return setTitle(0, idx, value);
else
{
//줄값이 필요하다
var row = (int)(Math.Floor((double)(idx / ColumnCount)));
var col = idx % ColumnCount;
return setTitle(row, col, value);
}
}
public void setValue(bool[] value)
{
var v = new UInt16[value.Length];
for (int i = 0; i < value.Length; i++)
v[i] = (UInt16)(value[i] ? 1 : 0);
_values = v;
//값이 잇으니 enable 한다
for (int i = 0; i < value.Length; i++)
{
if (i < Items.Length)
this.Items[i].Enable = true;
}
}
public void setValue(UInt16[] value)
{
_values = value;
for (int i = 0; i < value.Length; i++)
{
if (i < Items.Length)
this.Items[i].Enable = true;
}
}
public Boolean setValue(int idx, ushort value)
{
if (idx >= _values.Length || idx >= this.Items.Length) return false;
this._values[idx] = value;
this.Items[idx].Enable = true;
return true;
}
public void ClearValue(ushort defaultValue = 0)
{
if (_values != null)
for (int i = 0; i < _values.Length; i++)
_values[i] = defaultValue;
}
public void ClearTitle(string defaultValue = "")
{
if (_values != null)
for (int i = 0; i < _titles.Length; i++)
_titles[i] = defaultValue;
}
public void setValue(ushort value)
{
for (int i = 0; i < _values.Length; i++)
this._values[i] = value;
}
public void setItemEnable(int idx, bool value)
{
if (idx >= _values.Length || idx >= this.Items.Length) return;
this.Items[idx].Enable = value;
}
/// <summary>
/// 지정된 컬러태그값을 입력한다.
/// </summary>
/// <param name="idx"></param>
/// <param name="tagString"></param>
/// <returns></returns>
public Boolean setValue(int idx, string tagString)
{
//동일태그값을 찾는다
if (idx >= _values.Length) return false;
int value = -1;
for (int i = 0; i < ColorList.Length; i++)
if (ColorList[i].Remark.ToLower() == tagString.ToLower())
{
value = i;
break;
}
if (value != -1)
{
this._values[idx] = (ushort)value;
this.Items[idx].Enable = true;
return true;
}
else return false;
}
public Boolean setValue(int idx, bool value)
{
return setValue(idx, (ushort)(value ? 1 : 0));
}
public Boolean setValue(int row, int col, ushort value)
{
var idx = row * this.ColumnCount + col;
return setValue(idx, value);
}
public Boolean setValueToggle(int row, int col, ushort value1, ushort value2)
{
var idx = row * this.ColumnCount + col;
if (getValue(idx) == value1) return setValue(idx, value2);
else return setValue(idx, value1);
}
public Boolean setValue(int row, int col, bool value)
{
var idx = row * this.ColumnCount + col;
return setValue(idx, (ushort)(value ? 1 : 0));
}
public Boolean setValue(int row, int col, string value)
{
var idx = row * this.ColumnCount + col;
return setValue(idx, value);
}
public ushort getValue(int idx)
{
if (idx >= _values.Length) return 0;
return _values[idx];
}
public ushort getValue(int row, int col)
{
var idx = row * this.ColumnCount + col;
return getValue(idx);
}
[Category("arFrame")]
public bool ShowIndexString { get { return _showIndexString; } set { _showIndexString = value; Invalidate(); } }
[Category("arFrame"), DisplayName("테두리 굵기")]
public int BorderSize { get { return bordersize; } set { this.bordersize = value; Invalidate(); } }
[Category("arFrame"), DisplayName("메뉴 테두리 굵기")]
public int MenuBorderSize { get { return menubordersize; } set { this.menubordersize = value; Invalidate(); } }
[Category("arFrame"), DisplayName("메뉴 간격")]
public int MenuGap { get { return menugap; } set { this.menugap = value; RemakeChartRect(); Invalidate(); } }
[Category("arFrame"), DisplayName("글자를 이미지 다음에 표시"), Description("이미지가 있는 경우 해당 이미지 옆에 글자를 붙입니다")]
public Boolean TextAttachToImage { get { return textattachtoimage; } set { this.textattachtoimage = value; Invalidate(); } }
[Category("arFrame"), DisplayName("색상-테두리")]
public System.Drawing.Color BorderColor { get { return bordercolor; } set { this.bordercolor = value; Invalidate(); } }
[Category("arFrame"), DisplayName("내부 여백")]
public new System.Windows.Forms.Padding Padding { get { return padding; } set { this.padding = value; RemakeChartRect(); Invalidate(); } }
[Category("arFrame"), DisplayName("색상-전체배경색")]
public override System.Drawing.Color BackColor { get { return backcolor; } set { this.backcolor = value; Invalidate(); } }
[Category("arFrame"), DisplayName("색상-글자(그림자)")]
public System.Drawing.Color ShadowColor { get { return _shadowColor; } set { _shadowColor = value; this.Invalidate(); } }
[Category("arFrame"), DisplayName("색상-글자")]
public override Color ForeColor { get { return base.ForeColor; } set { base.ForeColor = value; } }
[Category("arFrame"), DisplayName("색상-글자(번호)")]
public Color ForeColorPin { get { return foreColorPin; } set { foreColorPin = value; } }
[Category("arFrame"), DisplayName("글꼴-번호")]
public Font FontPin { get { return fontPin; } set { fontPin = value; Invalidate(); } }
[Category("arFrame"), DisplayName("글꼴-항목")]
public override Font Font { get { return base.Font; } set { base.Font = value; Invalidate(); } }
private int mouseOverItemIndex = -1;
public GridView()
{
InitializeComponent();
// Set Optimized Double Buffer to reduce flickering
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
// Redraw when resized
this.SetStyle(ControlStyles.ResizeRedraw, true);
//값과 이름은 외부의 값을 사용한다
ResetArray();
if (MinimumSize.Width == 0 || MinimumSize.Height == 0)
MinimumSize = new Size(100, 50);
}
void ResetArray()
{
if (this._values != null) Array.Resize(ref this._values, itemCount);// = new UInt16[itemCount];
// if (this._titles != null) Array.Resize(ref this._titles, itemCount);//
// if (this._names != null) Array.Resize(ref this._names, itemCount);//
}
int itemCount { get { return ColumnCount * RowCount; } }
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
RemakeChartRect();
}
public event EventHandler<ItemClickEventArgs> ItemClick;
public class ItemClickEventArgs : EventArgs
{
public int idx { get; set; }
public GridViewItem Item { get; set; }
public ItemClickEventArgs(int idx_, GridViewItem item)
{
this.Item = item;
this.idx = idx_;
}
}
protected override void OnMouseClick(MouseEventArgs e)
{
//마우스클릭시 해당 버튼을 찾아서 반환한다.
if (Items == null || Items.Length < 1) return;
for (int i = 0; i < Items.Length; i++)
{
var rect = Items[i].rect;//[i];
if (rect.Contains(e.Location))
{
var menu = Items[i];
//미사용개체는 이벤트를 아에 발생하지 않는다
if (menu.Enable == true && ItemClick != null)
ItemClick(this, new ItemClickEventArgs(i, menu));
break;
}
}
}
protected override void OnMouseLeave(EventArgs e)
{
this.mouseOverItemIndex = -1;
this.Invalidate();
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (Items == null || Items.Length < 1)
{
this.mouseOverItemIndex = -1;
return;
}
for (int i = 0; i < Items.Length; i++)
{
var rect = Items[i].rect;// rects[i];
if (rect.Contains(e.Location))
{
if (i != mouseOverItemIndex)
{
mouseOverItemIndex = i;
this.Invalidate();
}
break;
}
}
}
public void setItemTextAlign(int row, int col, System.Drawing.ContentAlignment TextAlign)
{
var item = this.Items.Where(t => t.row == row && t.col == col).FirstOrDefault();
if (item != null) item.TextAlign = TextAlign;
}
public void setItemTextAlign(System.Drawing.ContentAlignment TextAlign)
{
foreach (var item in this.Items)
item.TextAlign = TextAlign;
}
protected override void OnPaint(PaintEventArgs pe)
{
//배경그리기
//using (var sb = new System.Drawing.Drawing2D.LinearGradientBrush(DisplayRectangle, BackColor, BackColor2On, System.Drawing.Drawing2D.LinearGradientMode.Vertical))
pe.Graphics.FillRectangle(new SolidBrush(BackColor), DisplayRectangle);
if (Items == null)
{
pe.Graphics.DrawString("no items", this.Font, Brushes.Red, 100, 100);
return;
}
var items = Items.OrderBy(t => t.No);
foreach (var menu in items)
{
drawItem(menu.idx, pe.Graphics);
}
//테두리 그리기
if (BorderSize > 0)
{
pe.Graphics.DrawRectangle(new Pen(this.BorderColor, BorderSize),
this.DisplayRectangle.Left,
this.DisplayRectangle.Top,
this.DisplayRectangle.Width - 1,
this.DisplayRectangle.Height - 1);
}
}
public void drawItem(int itemIndex, Graphics g = null)
{
if (g == null) g = this.CreateGraphics();
var menu = this.Items[itemIndex];
if (menu.rect == RectangleF.Empty) return;
var rect = menu.rect;// rects[i];
var diplayText = string.Empty;
// if(_titles[1].Trim() != "")
// Console.WriteLine("sdf");
//타이틀이 줄번호별로 처리됨
if (_titles != null && menu.row < _titles.Length)
{
if (_titles[menu.row] == null) _titles[menu.row] = string.Empty;
var linebif = _titles[menu.row].Split('|');
if (menu.col < linebif.Length)
diplayText = linebif[menu.col];
}
UInt16 Value = 0;
if (_values != null && menu.idx < _values.Length) Value = _values[menu.idx];
//배경이 투명이 아니라면 그린다.
var bgColor1 = Color.FromArgb(30, 30, 30);// BackColor1Off;
var bgColor2 = Color.FromArgb(30, 30, 30);// BackColor2Off;
//해당 값에 따른 컬러값을 읽는다.
if (ColorList != null && Value < ColorList.Length)
{
bgColor1 = this.ColorList[Value].BackColor1;
bgColor2 = this.ColorList[Value].BackColor2;
}
using (var sb = new System.Drawing.Drawing2D.LinearGradientBrush(rect, bgColor1, bgColor2, System.Drawing.Drawing2D.LinearGradientMode.Vertical))
g.FillRectangle(sb, rect);
// if (mouseOverItemIndex == menu.idx)
// this.Cursor = Cursors.Hand;
// else
// this.Cursor = Cursors.Arrow;
//테두리를 그리는 속성과 트기가 설정된 경우에만 표시
//if (mouseOverItemIndex == i)
// {
// pe.Graphics.DrawRectangle(new Pen(Color.DeepSkyBlue), rect.Left, rect.Top, rect.Width, rect.Height);
//}
//else
{
if (MenuBorderSize > 0)
{
using (var p = new Pen(BorderColor, MenuBorderSize))
g.DrawRectangle(p, rect.Left, rect.Top, rect.Width, rect.Height);
}
}
//인덱스번호 출력
if (ShowIndexString && _names != null && menu.idx < _names.Length)
{
//표시글자
var idxstr = string.Format("[{0}] {1}", menu.idx, _names[menu.idx]);
//그림자 추가
if (ShadowColor != System.Drawing.Color.Transparent)
g.DrawString(idxstr, FontPin, new SolidBrush(ShadowColor), menu.rect.Left + 4, menu.rect.Top + 4);
//일반글자표시
g.DrawString(idxstr, FontPin, new SolidBrush(this.ForeColorPin), menu.rect.Left + 3, menu.rect.Top + 3);
}
if (diplayText != "")
{
using (StringFormat sf = new StringFormat(StringFormatFlags.NoClip))
{
//글자를 텍스트 이후에 붙이는 거라면?
if (menu.TextAlign == ContentAlignment.BottomCenter || menu.TextAlign == ContentAlignment.BottomLeft ||
menu.TextAlign == ContentAlignment.BottomRight) sf.LineAlignment = StringAlignment.Far;
else if (menu.TextAlign == ContentAlignment.MiddleCenter || menu.TextAlign == ContentAlignment.MiddleLeft ||
menu.TextAlign == ContentAlignment.MiddleRight) sf.LineAlignment = StringAlignment.Center;
else if (menu.TextAlign == ContentAlignment.TopCenter || menu.TextAlign == ContentAlignment.TopLeft ||
menu.TextAlign == ContentAlignment.TopRight) sf.LineAlignment = StringAlignment.Near;
if (menu.TextAlign == ContentAlignment.BottomCenter || menu.TextAlign == ContentAlignment.MiddleCenter ||
menu.TextAlign == ContentAlignment.TopCenter) sf.Alignment = StringAlignment.Center;
else if (menu.TextAlign == ContentAlignment.BottomLeft || menu.TextAlign == ContentAlignment.MiddleLeft ||
menu.TextAlign == ContentAlignment.TopLeft) sf.Alignment = StringAlignment.Near;
else if (menu.TextAlign == ContentAlignment.BottomRight || menu.TextAlign == ContentAlignment.MiddleRight ||
menu.TextAlign == ContentAlignment.TopRight) sf.Alignment = StringAlignment.Far;
//그림자 추가
if (ShadowColor != System.Drawing.Color.Transparent)
g.DrawString(diplayText, this.Font, new SolidBrush(ShadowColor),
new RectangleF((float)(rect.Left + 1f), (float)(rect.Top + 1f), (float)rect.Width, (float)rect.Height), sf);
g.DrawString($"{diplayText}", this.Font, new SolidBrush(ForeColor), rect, sf);
}
}
if (showDebugInfo)
{
g.DrawString(Value.ToString(), this.fontPin, Brushes.SkyBlue, rect.Left, rect.Top);
}
}
/// <summary>
/// arFrame 전용 속성값을 복사 합니다
/// </summary>
/// <param name="ctl"></param>
public void copyTo(GridView ctl)
{
ctl.backcolor = this.backcolor;
ctl.menugap = this.menugap;
ctl.Items = this.Items;
ctl.menubordersize = this.menubordersize;
ctl.padding = this.padding;
ctl.ForeColor = this.ForeColor;
ctl.Font = this.Font;
ctl.TextAttachToImage = this.TextAttachToImage;
ctl.bordercolor = this.bordercolor;
ctl.bordersize = this.bordersize;
}
public void RemakeChartRect()
{
if (DisplayRectangle == Rectangle.Empty) return;
double x = 0;
double y = 0;
double w = DisplayRectangle.Width / (ColumnCount * 1.0);
double h = DisplayRectangle.Height / (RowCount * 1.0);
//아이템갯수가 달라졌으므로 다시 갱신해야함
GridViewItem[] item = new GridViewItem[RowCount * ColumnCount];
if(arVeriticalDraw)
{
for (int c = 0; c < ColumnCount; c++)
{
for (int r = 0; r < RowCount; r++)
{
int idx = c * ColumnCount + r;
item[idx] = new GridViewItem(idx, r, c);
if (this.Items != null && idx < this.Items.Length)
item[idx].Enable = this.Items[idx].Enable; // false;
else
item[idx].Enable = false;
item[idx].Padding = new Padding(0, 0, 0, 0);
item[idx].TextAlign = ContentAlignment.MiddleCenter;
x = (c * w);
y = (r * h);
item[idx].Dirty = true;
item[idx].rect = new RectangleF((float)x, (float)y, (float)w, (float)h);
}
}
}
else
{
for (int r = 0; r < RowCount; r++)
{
for (int c = 0; c < ColumnCount; c++)
{
int idx = r * ColumnCount + c;
item[idx] = new GridViewItem(idx, r, c);
if (this.Items != null && idx < this.Items.Length)
item[idx].Enable = this.Items[idx].Enable; // false;
else
item[idx].Enable = false;
item[idx].Padding = new Padding(0, 0, 0, 0);
item[idx].TextAlign = ContentAlignment.MiddleCenter;
x = (c * w);
y = (r * h);
item[idx].Dirty = true;
item[idx].rect = new RectangleF((float)x, (float)y, (float)w, (float)h);
}
}
}
this.Items = item;
this.Invalidate();
}
}
}