From c6d6abc8dd79b6ff399242a0dd2e0ebbcaf62864 Mon Sep 17 00:00:00 2001
From: and3md <and3md@gmail.com>
Date: Tue, 18 Jul 2017 15:22:06 +0200
Subject: [PATCH] New charts module with SimpleBarChart.

---
 examples/example1/src/example1.d |  46 ++-
 src/dlangui/widgets/charts.d     | 482 +++++++++++++++++++++++++++++++
 views/res/theme_dark.xml         |   9 +
 views/res/theme_default.xml      |  10 +
 4 files changed, 546 insertions(+), 1 deletion(-)
 create mode 100644 src/dlangui/widgets/charts.d

diff --git a/examples/example1/src/example1.d b/examples/example1/src/example1.d
index fb7bed77..b853b2f4 100644
--- a/examples/example1/src/example1.d
+++ b/examples/example1/src/example1.d
@@ -1092,9 +1092,53 @@ void main()
         tree.items.selectItem(tree.items.child(0));
 
         tabs.addTab(treeLayout, "Tree"d);
+        //==========================================================================
+        // charts example
+        SimpleBarChart barChart1 = new SimpleBarChart("barChart1","SimpleBarChart Example"d);
+        barChart1.addBar(12.0, makeRGBA(255,0,0,0), "Red bar"d);
+        barChart1.addBar(24.0, makeRGBA(0,255,0,0), "Green bar"d);
+        barChart1.addBar(5.0, makeRGBA(0,0,255,0), "Blue bar"d);
+        barChart1.addBar(12.0, makeRGBA(230,126,34,0), "Orange bar"d);
+        //barChart1.layoutWidth = FILL_PARENT;
+        //barChart1.layoutHeight = FILL_PARENT;
+        
+        SimpleBarChart barChart2 = new SimpleBarChart("barChart2","SimpleBarChart Example - long descriptions"d);
+        barChart2.addBar(12.0, makeRGBA(255,0,0,0), "Red bar\n(12.0)"d);
+        barChart2.addBar(24.0, makeRGBA(0,255,0,0), "Green bar\n(24.0)"d);
+        barChart2.addBar(5.0, makeRGBA(0,0,255,0), "Blue bar\n(5.0)"d);
+        barChart2.addBar(12.0, makeRGBA(230,126,34,0), "Orange bar\n(12.0)\nlong long long description added here"d);
 
-
+        SimpleBarChart barChart3 = new SimpleBarChart("barChart3","SimpleBarChart Example with axis ratio 0.3"d);
+        barChart3.addBar(12.0, makeRGBA(255,0,0,0), "Red bar"d);
+        barChart3.addBar(24.0, makeRGBA(0,255,0,0), "Green bar"d);
+        barChart3.addBar(5.0, makeRGBA(0,0,255,0), "Blue bar"d);
+        barChart3.addBar(12.0, makeRGBA(230,126,34,0), "Orange bar"d);
+        barChart3.axisRatio = 0.3;
+        
+        SimpleBarChart barChart4 = new SimpleBarChart("barChart4","SimpleBarChart Example with axis ratio 1.3"d);
+        barChart4.addBar(12.0, makeRGBA(255,0,0,0), "Red bar"d);
+        barChart4.addBar(24.0, makeRGBA(0,255,0,0), "Green bar"d);
+        barChart4.addBar(5.0, makeRGBA(0,0,255,0), "Blue bar"d);
+        barChart4.addBar(12.0, makeRGBA(230,126,34,0), "Orange bar"d);
+        barChart4.axisRatio = 1.3;
+                
+        HorizontalLayout chartsLayout = new HorizontalLayout("CHARTS");
+        chartsLayout.layoutWidth = FILL_PARENT;
+        chartsLayout.layoutHeight = FILL_PARENT;
+        
+        VerticalLayout chartColumn1 = new VerticalLayout();
+        VerticalLayout chartColumn2 = new VerticalLayout();
+        
+        chartColumn1.addChild(barChart1);
+        chartColumn1.addChild(barChart2);
+        chartsLayout.addChild(chartColumn1);
+        chartColumn2.addChild(barChart3);
+        chartColumn2.addChild(barChart4);
+        chartsLayout.addChild(chartColumn2);
+        tabs.addTab(chartsLayout, "Charts"d);
+        
         static if (BACKEND_GUI) {
+         
             tabs.addTab((new SampleAnimationWidget("tab6")).layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT), "TAB_ANIMATION"c);
 
             CanvasWidget canvas = new CanvasWidget("canvas");
diff --git a/src/dlangui/widgets/charts.d b/src/dlangui/widgets/charts.d
new file mode 100644
index 00000000..5e59c24c
--- /dev/null
+++ b/src/dlangui/widgets/charts.d
@@ -0,0 +1,482 @@
+// Written in the D programming language.
+
+/**
+This module contains charts widgets implementation.
+Currently only SimpleBarChart.
+
+
+Synopsis:
+
+----
+import dlangui.widgets.charts;
+
+// creation of simple bar chart
+SimpleBarChart chart = new SimpleBarChart("chart");
+
+// add bars
+chart.addBar(12.2, makeRGBA(255, 0, 0, 0), "new bar"c);
+
+// update bar with index 0
+chart.updateBar(0, 10, makeRGBA(255, 255, 0, 0), "new bar updated"c);
+chart.updateBar(0, 20);
+
+// remove bars with index 0
+chart.removeBar(0, 20);
+
+// change title
+chart.title = "new title"d;
+
+// change min axis ratio
+chart.axisRatio = 0.3; // y axis length will be 0.3 of x axis
+
+----
+
+Copyright: Andrzej Kilijański, 2017
+License:   Boost License 1.0
+Authors:   Andrzej Kilijański, and3md@gmail.com
+*/
+
+module dlangui.widgets.charts;
+
+import dlangui.widgets.widget;
+import std.math;
+import std.algorithm.comparison;
+import std.algorithm : remove;
+import std.conv;
+
+class SimpleBarChart : Widget {
+
+    this(string ID = null) {
+        super(ID);
+        clickable = false;
+        focusable = false;
+        trackHover = false;
+        styleId = "SIMPLE_BAR_CHART";
+        _axisX.arrowSize = 1;
+        title =  "New chart"d;
+        measureTextToSetWidgetSize();
+    }
+    
+    this(string ID, string titleResourceId) {
+        this(ID);
+        title = UIString.fromId(titleResourceId);
+    }
+    
+    this(string ID, dstring title) {
+        this(ID);
+        this.title = UIString.fromRaw(title);
+    }
+    
+    this(string ID, UIString title) {
+        this(ID);
+        this.title = title;
+    }
+
+    struct BarData {
+        double y;
+        UIString title;
+        private Point _titleSize;
+        uint color;
+    
+        this (double y, uint color, UIString title) {
+            this.y = y;
+            this.color = color;
+            this.title = title;
+        }
+    }
+        
+    protected BarData[] _bars;
+    protected double _maxY = 0;
+
+    size_t barCount() {
+        return _bars.length;
+    }
+    
+    void addBar(double y, uint color, UIString barTitle) {
+        if (y < 0)
+            return; // current limitation only positive values
+        _bars ~= BarData(y, color, barTitle);
+        if (y > _maxY)
+            _maxY = y;
+        requestLayout();
+    }
+
+    void addBar(double y, uint color, string barTitle) { 
+        addBar(y, color, UIString.fromId(barTitle));
+    }
+            
+    void addBar(double y, uint color, dstring barTitle) {
+        addBar(y, color, UIString.fromRaw(barTitle));
+    }
+    
+    void removeBar(size_t index) {
+        _bars = remove(_bars, index);
+        // update _maxY 
+        _maxY = 0;
+        foreach (ref bar ; _bars) {
+            if (bar.y > _maxY)
+                _maxY = bar.y;
+        }
+        requestLayout();
+    }
+
+    void updateBar(size_t index, double y, uint color, string barTitle) {
+        updateBar(index, y, color, UIString.fromId(barTitle));
+    }
+        
+    void updateBar(size_t index, double y, uint color, dstring barTitle) {
+        updateBar(index, y, color, UIString.fromRaw(barTitle));
+    }
+    
+    void updateBar(size_t index, double y, uint color, UIString barTitle) {
+        if (y < 0)
+            return; // current limitation only positive values
+        _bars[index].y = y;
+        _bars[index].color = color;
+        _bars[index].title = barTitle;
+        
+        // update _maxY
+        _maxY = 0;
+        foreach (ref bar ; _bars) {
+            if (bar.y > _maxY)
+                _maxY = bar.y;
+        }
+        requestLayout();
+    }
+    
+    void updateBar(size_t index, double y) {
+        if (y < 0)
+            return; // curent limitation only positive values
+        _bars[index].y = y;
+        
+        // update _maxY
+        _maxY = 0;
+        foreach (ref bar ; _bars) {
+            if (bar.y > _maxY)
+                _maxY = bar.y;
+        }
+        requestLayout();
+    }
+        
+    protected UIString _title;
+    protected bool _showTitle = true;
+    protected Point _titleSize;
+    protected int _marginAfterTitle = 2;
+    
+    /// set title to show
+    @property Widget title(string s) {  
+        return title(UIString.fromId(s));
+    }
+   
+    @property Widget title(dstring s) { 
+        return title(UIString.fromRaw(s));
+    }
+    
+    /// set title to show
+    @property Widget title(UIString s) { 
+        _title = s;
+        measureTitleSize();
+        if (_showTitle)
+            requestLayout();
+        return this;
+    }
+    
+    /// get title value
+    @property dstring title() {
+        return _title;
+    }
+    
+    /// show title?
+    @property bool showTitle() {
+        return _showTitle;
+    }
+    
+    @property void showTitle(bool show) {
+        if (_showTitle != show) {
+            _showTitle = show;
+            requestLayout();
+        }
+    }
+       
+    override protected void handleFontChanged() {
+        measureTitleSize();
+        measureTextToSetWidgetSize();
+    }
+    
+    protected void measureTitleSize() {
+        FontRef font = font();
+        _titleSize = font.textSize(_title, MAX_WIDTH_UNSPECIFIED, 4, 0, textFlags); //todo: more than one line title support
+    }
+    
+    @property uint chartBackgroundColor() {return ownStyle.customColor("chart_background_color"); }
+    
+    @property Widget chartBackgroundColor(uint newColor) {
+        ownStyle.setCustomColor("chart_background_color",newColor);
+        invalidate();
+        return this;
+    }
+    
+    @property uint chartAxisColor() {return ownStyle.customColor("chart_axis_color"); }
+    
+    @property Widget chartAxisColor(uint newColor) {
+        ownStyle.setCustomColor("chart_axis_color",newColor);
+        invalidate();
+        return this;
+    }
+    
+    @property uint chartSegmentTagColor() {return ownStyle.customColor("chart_segment_tag_color"); }
+    
+    @property Widget chartSegmentTagColor(uint newColor) {
+        ownStyle.setCustomColor("chart_segment_tag_color",newColor);
+        invalidate();
+        return this;
+    }
+    
+    struct AxisData {
+        Point maxDescriptionSize = Point(30,20);
+        int thickness = 1;
+        int arrowSize = 20;
+        int segmentTagLength = 4;
+        int zeroValueDist = 3;
+        int lengthFromZeroToArrow = 200;
+    }
+    
+    AxisData _axisX;
+    AxisData _axisY;
+
+    protected int _axisYMaxValueDescWidth = 30; 
+    protected int _axisYAvgValueDescWidth = 30;
+    
+    protected double _axisRatio = 0.6;
+    
+    @property double axisRatio() {
+        return _axisRatio;
+    }
+    
+    @property void axisRatio(double newRatio) {
+        _axisRatio = newRatio;
+        requestLayout();
+    }
+    
+    protected int _minBarWidth = 10;
+    protected int _barWidth = 10;
+    protected int _barDistance = 3;
+    
+    protected int _axisXMinWfromZero = 150;
+    protected int _axisYMinDescWidth = 30;
+            
+    protected dstring _textToSetDescLineSize = "aaaaaaaaaa";
+    protected Point _measuredTextToSetDescLineSize;
+    
+    @property dstring textToSetDescLineSize() {
+        return _textToSetDescLineSize;
+    }
+    
+    @property void textToSetDescLineSize(dstring newText) {
+        _textToSetDescLineSize = newText;
+        measureTextToSetWidgetSize();
+        requestLayout();
+    }
+    
+    private int[] _charWidths;
+    protected Point measureTextToSetWidgetSize() {
+        FontRef font = font();
+        _charWidths.length = _textToSetDescLineSize.length;
+        int charsMeasured = font.measureText(_textToSetDescLineSize, _charWidths, MAX_WIDTH_UNSPECIFIED, 4);
+        _measuredTextToSetDescLineSize.x = charsMeasured > 0 ? _charWidths[charsMeasured - 1]: 0;
+        _measuredTextToSetDescLineSize.y = font.height;
+        return _measuredTextToSetDescLineSize;
+    }
+    
+    override void measure(int parentWidth, int parentHeight) { 
+        FontRef font = font();
+                
+        int mWidth = minWidth;
+        int mHeight = minHeight;
+        
+        int chartW = 0;
+        int chartH = 0;
+        
+        _axisY.maxDescriptionSize = measureAxisYDesc();
+        
+        int usedWidth = _axisY.maxDescriptionSize.x + _axisY.thickness + _axisY.segmentTagLength + _axisX.zeroValueDist + margins.left + padding.left + margins.right + padding.right + _axisX.arrowSize;
+        
+        int currentMinBarWidth = max(_minBarWidth, _measuredTextToSetDescLineSize.x);
+        _axisX.maxDescriptionSize.y = _measuredTextToSetDescLineSize.y;
+        
+        // axis length
+        _axisX.lengthFromZeroToArrow = cast(uint) barCount * (currentMinBarWidth + _barDistance);
+        
+        if (_axisX.lengthFromZeroToArrow < _axisXMinWfromZero) {
+            _axisX.lengthFromZeroToArrow = _axisXMinWfromZero;
+            if (barCount > 0)
+                _barWidth = cast (int) ((_axisX.lengthFromZeroToArrow - (_barDistance * barCount)) / barCount);
+        }
+        
+        // minWidth and minHeight check
+        
+        if (minWidth > _axisX.lengthFromZeroToArrow + usedWidth) {
+            _axisX.lengthFromZeroToArrow = minWidth-usedWidth;
+            if (barCount > 0)
+                _barWidth = cast (int) ((_axisX.lengthFromZeroToArrow - (_barDistance * barCount)) / barCount);
+        }
+        
+        // width FILL_PARENT support
+        if (parentWidth != SIZE_UNSPECIFIED && layoutWidth == FILL_PARENT) {
+            if (_axisX.lengthFromZeroToArrow < parentWidth - usedWidth) {
+                _axisX.lengthFromZeroToArrow = parentWidth - usedWidth;
+            if (barCount > 0)
+                _barWidth = cast (int) ((_axisX.lengthFromZeroToArrow - (_barDistance * barCount)) / barCount);
+            }
+        }
+        
+        
+        // initialize axis y length
+        _axisY.lengthFromZeroToArrow = cast(int) round(_axisRatio * _axisX.lengthFromZeroToArrow);
+        
+        // is axis Y enought long 
+        int usedHeight = _axisX.maxDescriptionSize.y + _axisX.thickness + _axisX.segmentTagLength + _axisY.zeroValueDist + ((_showTitle) ? _titleSize.y + _marginAfterTitle : 0) + margins.top + padding.top + margins.bottom + padding.bottom + _axisY.arrowSize; 
+        if (minHeight > _axisY.lengthFromZeroToArrow + usedHeight) {
+            _axisY.lengthFromZeroToArrow = minHeight - usedHeight;
+            _axisX.lengthFromZeroToArrow = cast (int) round(_axisY.lengthFromZeroToArrow / _axisRatio);
+        }
+        
+        // height FILL_PARENT support
+        if (parentHeight != SIZE_UNSPECIFIED && layoutHeight == FILL_PARENT) {
+            if (_axisY.lengthFromZeroToArrow < parentHeight - usedHeight)
+                _axisY.lengthFromZeroToArrow = parentHeight - usedHeight;
+        }
+
+        if (barCount > 0)
+            _barWidth = cast (int) ((_axisX.lengthFromZeroToArrow - (_barDistance * barCount)) / barCount);
+                
+        // compute X axis max description height
+        Log.d("barW ",_barWidth);
+        _axisX.maxDescriptionSize = measureAxisXDesc();
+        
+        // compute chart size
+        chartW = _axisY.maxDescriptionSize.x + _axisY.thickness + _axisY.segmentTagLength + _axisX.zeroValueDist + _axisX.lengthFromZeroToArrow + _axisX.arrowSize;
+        if (_showTitle && chartW < _titleSize.y)
+            chartW = _titleSize.y;
+        
+        chartH = _axisX.maxDescriptionSize.y + _axisX.thickness + _axisX.segmentTagLength + _axisY.zeroValueDist + _axisY.lengthFromZeroToArrow + ((_showTitle) ? _titleSize.y + _marginAfterTitle : 0) + _axisY.arrowSize;
+        measuredContent(parentWidth, parentHeight, chartW, chartH);
+    }
+
+
+    protected Point measureAxisXDesc() {
+        Point sz;
+        foreach (ref bar ; _bars) {
+            bar._titleSize = font.measureMultilineText(bar.title, 0, _barWidth, 4, 0, textFlags);
+            if (sz.y < bar._titleSize.y)
+                sz.y = bar._titleSize.y; 
+            if (sz.x < bar._titleSize.x)
+                sz.x = bar._titleSize.y; 
+        }
+        return sz;
+    }
+        
+    protected Point measureAxisYDesc() {
+        int maxDescWidth = _axisYMinDescWidth;
+        double currentMaxValue = _maxY;
+        if (approxEqual(_maxY, 0, 0.0000001, 0.0000001))
+            currentMaxValue = 100;
+            
+        Point sz = font.textSize(to!dstring(currentMaxValue), MAX_WIDTH_UNSPECIFIED, 4, 0, textFlags); 
+        if (maxDescWidth<sz.x)
+            maxDescWidth=sz.x;
+        _axisYMaxValueDescWidth = sz.x;
+        sz = font.textSize(to!dstring(currentMaxValue / 2), MAX_WIDTH_UNSPECIFIED, 4, 0, textFlags);
+        if (maxDescWidth<sz.x)
+            maxDescWidth=sz.x;
+        _axisYAvgValueDescWidth = sz.x;
+        return Point(maxDescWidth, sz.y);
+    }
+        
+    protected int barYValueToPixels(int axisInPixels, double barYValue ) {
+        double currentMaxValue = _maxY;
+        if (approxEqual(_maxY, 0, 0.0000001, 0.0000001))
+            currentMaxValue = 100;
+
+        double pixValue = axisInPixels / currentMaxValue;
+        return cast(int) round(barYValue * pixValue);
+    }
+    
+    override void onDraw(DrawBuf buf) {
+        if (visibility != Visibility.Visible)
+            return;
+        super.onDraw(buf);
+        
+        Rect rc = _pos;
+        applyMargins(rc);
+        applyPadding(rc);
+        
+        auto saver = ClipRectSaver(buf, rc, alpha);
+        
+        FontRef font = font();
+        if (_showTitle) 
+            font.drawText(buf, rc.left+ (_measuredWidth - _titleSize.x)/2  , rc.top, _title, textColor, 4, 0, textFlags);
+        
+        // draw axises and 
+        int x1 = rc.left + _axisY.maxDescriptionSize.x + _axisY.segmentTagLength;
+        int x2 = rc.left + _axisY.maxDescriptionSize.x + _axisY.segmentTagLength + _axisY.thickness + _axisX.zeroValueDist + _axisX.lengthFromZeroToArrow + _axisX.arrowSize;
+        int y1 = rc.bottom - _axisX.maxDescriptionSize.y - _axisX.segmentTagLength - _axisX.thickness - _axisY.zeroValueDist - _axisY.lengthFromZeroToArrow - _axisY.arrowSize;
+        int y2 = rc.bottom - _axisX.maxDescriptionSize.y - _axisX.segmentTagLength;
+        
+        buf.fillRect(Rect(x1, y1, x2, y2), chartBackgroundColor);
+        
+        // y axis
+        buf.drawLine(Point(x1 + 1, y1), Point(x1 + 1, y2), chartAxisColor);
+        
+        // x axis
+        buf.drawLine(Point(x1, y2 - 1), Point(x2, y2 - 1), chartAxisColor);
+            
+        // top line - will be optional in the future
+        buf.drawLine(Point(x1, y1), Point(x2, y1), chartAxisColor);
+            
+        // right line - will be optional in the future
+        buf.drawLine(Point(x2, y1), Point(x2, y2), chartAxisColor);
+        
+        // draw bars
+        
+        int firstBarX = x1 + _axisY.thickness + _axisX.zeroValueDist;
+        int firstBarY = y2 - _axisX.thickness - _axisY.zeroValueDist;
+        
+        SimpleTextFormatter fmt;
+        foreach (ref bar ; _bars) {
+            // draw bar
+            buf.fillRect(Rect(firstBarX, firstBarY - barYValueToPixels(_axisY.lengthFromZeroToArrow, bar.y), firstBarX + _barWidth, firstBarY), bar.color);
+            
+            // draw x axis segment under bar
+            buf.drawLine(Point(firstBarX + _barWidth / 2, y2), Point(firstBarX + _barWidth / 2, rc.bottom - _axisX.maxDescriptionSize.y), chartSegmentTagColor);
+            
+            // draw x axis description
+            fmt.format(bar.title, font, 0, _barWidth, 4, 0, textFlags);
+            fmt.draw(buf, firstBarX + (_barWidth - bar._titleSize.x) / 2, rc.bottom -  _axisX.maxDescriptionSize.y + (_axisX.maxDescriptionSize.y - bar._titleSize.y) / 2, font, textColor, Align.HCenter);
+            
+            firstBarX += _barWidth + _barDistance;
+        }
+        
+        // segments on y axis and values (now only max and max/2)
+        double currentMaxValue = _maxY;
+        if (approxEqual(_maxY, 0, 0.0000001, 0.0000001))
+            currentMaxValue = 100;
+        
+        int yZero = rc.bottom - _axisX.maxDescriptionSize.y - _axisX.segmentTagLength - _axisX.thickness - _axisY.zeroValueDist;
+        int yMax = yZero - _axisY.lengthFromZeroToArrow;
+        int yAvg = (yZero + yMax) / 2;
+        
+        buf.drawLine(Point(rc.left + _axisY.maxDescriptionSize.x, yMax), Point(rc.left + _axisY.maxDescriptionSize.x + _axisY.segmentTagLength, yMax), chartSegmentTagColor);
+        buf.drawLine(Point(rc.left + _axisY.maxDescriptionSize.x, yAvg), Point(rc.left + _axisY.maxDescriptionSize.x + _axisY.segmentTagLength, yAvg), chartSegmentTagColor);
+        
+        font.drawText(buf, rc.left + (_axisY.maxDescriptionSize.x - _axisYMaxValueDescWidth), yMax - _axisY.maxDescriptionSize.y / 2, to!dstring(currentMaxValue), textColor, 4, 0, textFlags);
+        font.drawText(buf, rc.left + (_axisY.maxDescriptionSize.x - _axisYAvgValueDescWidth), yAvg - _axisY.maxDescriptionSize.y / 2, to!dstring(currentMaxValue / 2), textColor, 4, 0, textFlags);
+        
+    }
+
+    override void onThemeChanged() {
+        super.onThemeChanged();
+        handleFontChanged();
+    }
+}
+
diff --git a/views/res/theme_dark.xml b/views/res/theme_dark.xml
index ad4b52e4..111beeb2 100644
--- a/views/res/theme_dark.xml
+++ b/views/res/theme_dark.xml
@@ -299,6 +299,15 @@
         padding="1pt,1pt,1pt,1pt">
     </style>
     
+   <style id="SIMPLE_BAR_CHART"
+        padding="2pt,2pt,2pt,2pt"
+        margins="2pt,2pt,2pt,2pt"
+        minWidth="250pt"
+        >
+        <color id="chart_background_color" value="#262626"/>
+        <color id="chart_axis_color" value="#505255"/>
+        <color id="chart_segment_tag_color" value="#505255"/>
+   </style>
 
 </theme>
 
diff --git a/views/res/theme_default.xml b/views/res/theme_default.xml
index f6fc43f1..c3b1fa70 100644
--- a/views/res/theme_default.xml
+++ b/views/res/theme_default.xml
@@ -525,6 +525,16 @@
         <drawable id="progress_bar_indeterminate" value="#80C080"/>
         <drawable id="progress_bar_indeterminate_animation" value="progress_bar_gauge_animation.tiled"/>
     </style>
+
+   <style id="SIMPLE_BAR_CHART"
+        padding="2pt,2pt,2pt,2pt"
+        margins="2pt,2pt,2pt,2pt"
+        minWidth="250pt"
+        >
+        <color id="chart_background_color" value="#FFFFFF"/>
+        <color id="chart_axis_color" value="#C0C0C0"/>
+        <color id="chart_segment_tag_color" value="#C0C0C0"/>
+   </style>
     
 </theme>