[chronojump] Added CairoBars class
- From: Xavier de Blas <xaviblas src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [chronojump] Added CairoBars class
- Date: Fri, 16 Jul 2021 16:43:42 +0000 (UTC)
commit fa34e3d451c9f977146b8856ce9d023906b541c0
Author: Xavier de Blas <xaviblas gmail com>
Date: Fri Jul 16 18:43:17 2021 +0200
Added CairoBars class
src/Makefile.am | 1 +
src/gui/cairo/bars.cs | 363 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 364 insertions(+)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 2d49055d1..2f041aa70 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,6 +35,7 @@ SOURCES = \
gui/app1/runEncoder.cs\
gui/app1/runEncoderAnalyze.cs\
gui/app1/shortcuts.cs\
+ gui/cairo/bars.cs\
gui/cairo/generic.cs\
gui/cairo/jumpsDjOptimalFall.cs\
gui/cairo/jumpsRunsEvolution.cs\
diff --git a/src/gui/cairo/bars.cs b/src/gui/cairo/bars.cs
new file mode 100644
index 000000000..a4f000ab5
--- /dev/null
+++ b/src/gui/cairo/bars.cs
@@ -0,0 +1,363 @@
+
+/*
+ * This file is part of ChronoJump
+ *
+ * ChronoJump is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * ChronoJump is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Copyright (C) 2004-2021 Xavier de Blas <xaviblas gmail com>
+ */
+
+using System;
+using System.Collections.Generic; //List
+using Gtk;
+using Cairo;
+
+public abstract class CairoBars : CairoGeneric
+{
+ //used on construction
+ protected List<PointF> point_l;
+ protected List<string> names_l;
+
+ protected DrawingArea area;
+ protected string title;
+ //protected string jumpType;
+ //protected string runType;
+ protected string date;
+ protected Cairo.Color colorBackground;
+
+ protected Cairo.Context g;
+ protected const int textHeight = 14;
+ protected int lineWidthDefault = 2;
+ protected string xVariable = "";
+ protected string yVariable = "Height";
+ protected string xUnits = "";
+ protected string yUnits = "cm";
+
+ protected double minX = 1000000;
+ protected double maxX = 0;
+ protected double minY = 1000000;
+ protected double maxY = 0;
+ protected int graphWidth;
+ protected int graphHeight;
+
+ protected Cairo.Color black;
+ protected Cairo.Color gray99;
+ Cairo.Color white;
+ protected Cairo.Color red;
+ Cairo.Color blue;
+ protected Cairo.Color bluePlots;
+ protected Cairo.Color yellow;
+
+
+ public virtual void Do(string font)
+ {
+ }
+
+ protected void initGraph(string font, double widthPercent1)
+ {
+ initGraph(font, widthPercent1, true);
+ }
+ protected void initGraph(string font, double widthPercent1, bool clearDrawingArea)
+ {
+ this.font = font;
+ LogB.Information("Font: " + font);
+
+ outerMargins = 18; //blank space outside the axis.
+
+ //1 create context
+ g = Gdk.CairoHelper.Create (area.GdkWindow);
+
+ if(clearDrawingArea)
+ {
+ //2 clear DrawingArea (white)
+ g.SetSourceRGB(1,1,1);
+ g.Paint();
+ }
+
+ graphWidth = Convert.ToInt32(area.Allocation.Width * widthPercent1);
+ graphHeight = area.Allocation.Height;
+ LogB.Information(string.Format("graphWidth: {0}, graphHeight: {1}", graphWidth, graphHeight));
+
+ g.SetSourceRGB(0,0,0);
+ g.LineWidth = lineWidthDefault;
+
+ //4 prepare font
+ g.SelectFontFace(font, Cairo.FontSlant.Normal, Cairo.FontWeight.Normal);
+ g.SetFontSize(textHeight);
+
+ black = colorFromRGB(0,0,0);
+ gray99 = colorFromRGB(99,99,99);
+ white = colorFromRGB(255,255,255);
+ red = colorFromRGB(200,0,0);
+ blue = colorFromRGB(178, 223, 238); //lightblue
+ bluePlots = colorFromRGB(0, 0, 200);
+ yellow = colorFromRGB(255,238,102);
+ }
+
+ protected void findPointMaximums()
+ {
+ foreach(PointF p in point_l)
+ if(p.Y > maxY)
+ maxY = p.Y;
+
+ //points X start at 1
+ minX = 0;
+ maxX = point_l.Count + 1;
+
+ //bars Y have 0 at bottom
+ minY = 0;
+ }
+
+ protected void paintAxis(int width)
+ {
+ g.LineWidth = width;
+ g.MoveTo(outerMargins, outerMargins);
+ g.LineTo(outerMargins, graphHeight - outerMargins);
+ g.LineTo(graphWidth - outerMargins, graphHeight - outerMargins);
+ g.Stroke ();
+
+ g.SetFontSize(textHeight -2);
+ printText(2, Convert.ToInt32(outerMargins/2), 0, textHeight, getYAxisLabel(), g,
alignTypes.LEFT);
+ printXAxisText();
+ g.Stroke ();
+
+ g.SetFontSize(textHeight);
+ g.LineWidth = lineWidthDefault;
+ }
+
+ //this combined with paintVerticalGridLine is different on RaceAnalyzer
+ protected virtual void printXAxisText()
+ {
+ printText(graphWidth - Convert.ToInt32(outerMargins/2), graphHeight - outerMargins, 0,
textHeight,
+ getXAxisLabel(), g, alignTypes.LEFT);
+ }
+
+ protected string getXAxisLabel()
+ {
+ return getAxisLabel(xVariable, xUnits);
+ }
+ private string getYAxisLabel()
+ {
+ return getAxisLabel(yVariable, yUnits);
+ }
+ private string getAxisLabel(string variable, string units)
+ {
+ if(units == "")
+ return variable;
+ return string.Format("{0} ({1})", variable, units);
+ }
+
+ protected double calculatePaintY (double realY)
+ {
+ return graphHeight - outerMargins - UtilAll.DivideSafe(
+ (realY - minY) * (graphHeight - 2*outerMargins),
+ maxY - minY);
+ }
+
+ protected void printText (double x, double y, double height, int textHeight,
+ string text, Cairo.Context g, alignTypes align)
+ {
+ int moveToLeft = 0;
+ if(align == alignTypes.CENTER || align == alignTypes.RIGHT)
+ {
+ Cairo.TextExtents te;
+ te = g.TextExtents(text);
+
+ if(align == alignTypes.CENTER)
+ moveToLeft = Convert.ToInt32(te.Width/2);
+ else
+ moveToLeft = Convert.ToInt32(te.Width);
+ }
+
+ g.MoveTo( x - moveToLeft, ((y+y+height)/2) + textHeight/2 );
+ g.ShowText(text);
+ }
+
+ protected void plotBars()
+ {
+ //calculate separation between series and bar width
+ int distanceBetweenCols = Convert.ToInt32((graphWidth -
2*outerMargins)*(1+.5)/point_l.Count) -
+ Convert.ToInt32((graphWidth - 2*outerMargins)*(0+.5)/point_l.Count);
+
+ //int tctfSep = Convert.ToInt32(.3*distanceBetweenCols);
+ int barWidth = Convert.ToInt32(.5*distanceBetweenCols);
+ int barDesplLeft = Convert.ToInt32(.5*barWidth);
+
+ for(int i = 0; i < point_l.Count; i ++)
+ {
+ PointF p = point_l[i];
+
+ double x = (graphWidth - 2*outerMargins) * (p.X-.5)/point_l.Count - barDesplLeft +
outerMargins;
+ double y = calculatePaintY(p.Y);
+
+ drawRoundedRectangle (true, x, y, barWidth, graphHeight -y -outerMargins, 4, g,
colorBackground);
+
+ //print the result at the middle of the bar
+ plotResultOnBar(x + barWidth/2, y, graphHeight -outerMargins, p.Y);
+
+ //print the type at bottom
+ printText(x + barWidth/2, graphHeight -outerMargins + textHeight/2, 0, textHeight,
+ names_l[i], g, alignTypes.CENTER);
+
+ /*
+ x = Convert.ToInt32((graphWidth -
outerMargins)*(count+.5)/point_l.Count)-barDesplLeft+tctfSep;
+ y = calculatePaintY(p.Y);
+
+ LogB.Information(string.Format("blue: {0}, {1}, {2}, {3}", Convert.ToDouble(p.Y),
graphHeight, maxY, y));
+ drawRoundedRectangle (x, y, barWidth, graphHeight -y - outerMargins, 4, g, blue);
+ */
+ }
+ }
+
+ //adapted from http://www.mono-project.com/docs/tools+libraries/libraries/Mono.Cairo/cookbook/
+ //bottomFlat means to have rounded only on top
+ private static void drawRoundedRectangle (bool bottomFlat,
+ double x, double y, double width, double height,
+ double radius, Cairo.Context g, Cairo.Color color)
+ {
+ g.Save ();
+
+ //manage negative widths
+ if(width < 0)
+ {
+ x += width; //it will shift to the left (width is negative)
+ width *= -1;
+ }
+
+ if ((radius > height / 2) || (radius > width / 2))
+ radius = min (height / 2, width / 2);
+
+ g.MoveTo (x, y + radius);
+ g.Arc (x + radius, y + radius, radius, Math.PI, -Math.PI / 2);
+ g.LineTo (x + width - radius, y);
+ g.Arc (x + width - radius, y + radius, radius, -Math.PI / 2, 0);
+
+ if(bottomFlat)
+ {
+ g.LineTo (x + width, y + height);
+ g.LineTo (x, y + height);
+ } else {
+ g.LineTo (x + width, y + height - radius);
+ g.Arc (x + width - radius, y + height - radius, radius, 0, Math.PI / 2);
+ g.LineTo (x + radius, y + height);
+ g.Arc (x + radius, y + height - radius, radius, Math.PI / 2, Math.PI);
+ }
+
+ g.ClosePath ();
+ g.Restore ();
+
+ g.SetSourceRGB(color.R, color.G, color.B);
+ g.FillPreserve ();
+ g.SetSourceRGB(0, 0, 0);
+ g.LineWidth = 1;
+ g.Stroke ();
+ }
+ private static double min (params double[] arr)
+ {
+ int minp = 0;
+ for (int i = 1; i < arr.Length; i++)
+ if (arr[i] < arr[minp])
+ minp = i;
+
+ return arr[minp];
+ }
+
+ private void plotResultOnBar(double x, double y, double alto, double result)
+ {
+ Cairo.TextExtents te;
+ te = g.TextExtents(Util.TrimDecimals(result,2));
+
+ /*
+ * text and surrounding rect are in the middle of bar
+ * if bar is so small, then text and rect will not be fully shown
+ * for this reason, show rect and bar in a higher position
+ * use 2*lHeight in order to accomodate "Simulated" message below
+ */
+ double yStart = (y+alto)/2 - te.Height/2;
+ LogB.Information(string.Format("y: {0}, alto: {1}, yStart: {2}", y, alto, yStart));
+
+ if( (yStart + te.Height) > alto )
+ yStart = alto - te.Height;
+
+ g.Color = yellow;
+ g.Rectangle(x - te.Width/2, yStart-1, te.Width, te.Height+2);
+ g.Fill();
+
+ //write text
+ g.Color = black;
+ printText(x, yStart+te.Height/2, 0, Convert.ToInt32(te.Height),
+ Util.TrimDecimals(result, 2), g, alignTypes.CENTER);
+ }
+
+ protected void writeTitleAtTop()
+ {
+ printText(graphWidth/2 + outerMargins, textHeight/2, 0, textHeight,
+ title, g, alignTypes.CENTER);
+ }
+ /*
+ protected void writeTitleAtRight()
+ {
+ int ypos = -6;
+
+ //writeTextAtRight(ypos++, title, true);
+ //writeTextAtRight(ypos++, jumpTypeStr + " " + jumpType, false);
+ //writeTextAtRight(ypos++, date, false);
+
+ printText(graphWidth, Convert.ToInt32(graphHeight/2 + textHeight*2), 0, textHeight,
+ title, g, alignTypes.LEFT);
+ }
+ */
+}
+
+public class CairoBarsJustTesting : CairoBars
+{
+ //constructor when there are no points
+ public CairoBarsJustTesting (DrawingArea area, string font)
+ {
+ this.area = area;
+
+ LogB.Information("area is null:" + (area == null).ToString());
+ initGraph(font, .8);
+
+ endGraphDisposing(g);
+ }
+
+ //regular constructor
+ public CairoBarsJustTesting (List<PointF> point_l, List<string> names_l, DrawingArea area, string
title)
+ {
+ this.point_l = point_l;
+ this.names_l = names_l;
+ this.area = area;
+ this.title = title;
+
+ this.colorBackground = colorFromGdk(Config.ColorBackground); //but note if we are using
system colors, this will not match
+ }
+
+ public override void Do(string font)
+ {
+ LogB.Information("at CairoBarsJustTesting.Do");
+ initGraph(font, 1); //.8 if writeTextAtRight
+
+ findPointMaximums();
+ paintAxis(2);
+
+ g.Color = black;
+ plotBars();
+
+ writeTitleAtTop ();
+
+ endGraphDisposing(g);
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]