private void PbOnPaint(object sender, PaintEventArgs e) { _clickHandler.Reset(); var g = e.Graphics; g.Clear(Color.White); if (State.Info == null) { return; } var rectSize = new SizeF(RECT_SIZE, RECT_SIZE); Vector2 y_cursor = new Vector2(0, RECT_INDENT); var y_step = new Vector2(0, RECT_SIZE + RECT_INDENT); bool yIsOverflow() { return((y_cursor + y_step).Y > e.ClipRectangle.Height); } foreach (var trace in State.Log.EnumerateInRage(State.Pos, State.Pos + State.TracesInView)) { int linesNum = 1; Vector2 y_start = y_cursor; Vector2 x_start = new Vector2(TRACE_INFO_W + RECT_INDENT, 0); Vector2 x_cursor = x_start; Vector2 x_step = new Vector2(RECT_SIZE + RECT_INDENT, 0); bool notFullyDrawn = false; if (trace == null) { var rect = new RectangleF((x_cursor + y_cursor).ToPointF(), rectSize); g.FillRectangle(Brushes.LightGray, rect); } else { for (int i = 0; i < trace.Items.Count; i++) { //check if need to go to new line if ((x_cursor + x_step).X > e.ClipRectangle.Width) { //new line linesNum++; x_cursor = x_start; y_cursor += y_step; //do we need break here (y overflow) if (yIsOverflow()) { notFullyDrawn = true; break; } } var rect = new RectangleF((x_cursor + y_cursor).ToPointF(), rectSize); _clickHandler.PushItemRect(rect, trace, i); var rules = GetRulesForItem(trace, i).ToArray(); switch (rules.Length) { case 0: g.FillRectangle(Brushes.Gray, rect); break; case 2: case 3: { for (int j = 0; j < rules.Length; j++) { var partRect = new RectangleF(rect.X + rect.Width / rules.Length * j, rect.Y, rect.Width / rules.Length, rect.Height); g.FillRectangle(new SolidBrush(ColorTranslator.FromHtml(rules[j].Color)), partRect); } //two sided rect //var rect1 = new RectangleF(rect.X, rect.Y, rect.Width / 2, rect.Height); //var rect2 = new RectangleF(rect.X + rect.Width / 2, rect.Y, rect.Width / 2, rect.Height); //g.FillRectangle(new SolidBrush(rules[0].Color), rect1); //g.FillRectangle(new SolidBrush(rules[1].Color), rect2); break; } case 1: default: var bgColor = ColorTranslator.FromHtml(rules[0].Color); g.FillRectangle(new SolidBrush(bgColor), rect); var text = rules[0].Text; var textColor = bgColor.GetBrightness() > 0.5 ? Color.Black : Color.White; var font = new Font("Cosnsolas", 15); var fontNew = Util.FlexFont(0, 15, new Size((int)RECT_SIZE, (int)RECT_SIZE), text, font); var textSize = g.MeasureString(text, fontNew); var pos = new PointF(rect.X + rect.Width / 2 - textSize.Width / 2, rect.Y + rect.Height / 2 - textSize.Height / 2); g.DrawString(text, fontNew, new SolidBrush(textColor), pos); break; } //increment x pos x_cursor += x_step; } //draw trace left green line if (notFullyDrawn) { var start = y_start; var w = new Vector2(TRACE_INFO_W, 0); var h = y_cursor - new Vector2(0, RECT_INDENT) - y_start; var b = new ShapeBuilder() .MoveTo(start) .MoveBy(w) .MoveBy(h); //drawing /\/\/\/\ var fluct = TRACE_INFO_W / 4; var fluctUp = new Vector2(-fluct, -fluct); var fluctDown = new Vector2(-fluct, fluct); for (int i = 0; i < 4; i++) { if (i % 2 == 0) { b.MoveBy(fluctUp); } else { b.MoveBy(fluctDown); } } g.FillPolygon(new SolidBrush(Color.FromArgb(87, 116 + 40, 48)), b.GetPtsF()); } else { var start = y_start; var size = new SizeF(TRACE_INFO_W, (y_cursor + y_step - new Vector2(0, RECT_INDENT) - y_start).Y); var rect = new RectangleF(start.ToPointF(), size); _clickHandler.PushTraceRect(rect, trace); g.FillRectangle(new SolidBrush(Color.FromArgb(87, 116 + 40, 48)), rect); } } y_cursor += y_step; if (yIsOverflow()) { break; } } }