From 3d02726ad4dc3bc6a92d5b68ef8421ac4db44076 Mon Sep 17 00:00:00 2001
From: xuri <xuri.me@gmail.com>
Date: Fri, 14 Oct 2022 00:48:16 +0800
Subject: This closes #320, support custom chart axis font style

---
 chart.go      | 19 ++++++++++++++++---
 chart_test.go |  2 +-
 drawing.go    | 22 +++++++++++++++++-----
 file.go       |  4 ++--
 shape.go      | 28 +++-------------------------
 styles.go     | 18 ++++++------------
 table.go      |  2 +-
 xmlChart.go   | 45 ++++++++++++++++++++-------------------------
 xmlDrawing.go | 14 ++++++++++++--
 9 files changed, 78 insertions(+), 76 deletions(-)

diff --git a/chart.go b/chart.go
index 0caa505..ce11b59 100644
--- a/chart.go
+++ b/chart.go
@@ -750,22 +750,24 @@ func parseChartOptions(opts string) (*chartOptions, error) {
 //	reverse_order
 //	maximum
 //	minimum
+//	number_font
 //
 // The properties of y_axis that can be set are:
 //
 //	none
 //	major_grid_lines
 //	minor_grid_lines
-//	major_unit
+//	tick_label_skip
 //	reverse_order
 //	maximum
 //	minimum
+//	number_font
 //
 // none: Disable axes.
 //
-// major_grid_lines: Specifies major gridlines.
+// major_grid_lines: Specifies major grid lines.
 //
-// minor_grid_lines: Specifies minor gridlines.
+// minor_grid_lines: Specifies minor grid lines.
 //
 // major_unit: Specifies the distance between major ticks. Shall contain a positive floating-point number. The major_unit property is optional. The default value is auto.
 //
@@ -777,6 +779,17 @@ func parseChartOptions(opts string) (*chartOptions, error) {
 //
 // minimum: Specifies that the fixed minimum, 0 is auto. The minimum property is optional. The default value is auto.
 //
+// number_font: Specifies that the font of the horizontal and vertical axis. The properties of number_font that can be set are:
+//
+//	bold
+//	italic
+//	underline
+//	family
+//	size
+//	strike
+//	color
+//	vertAlign
+//
 // Set chart size by dimension property. The dimension property is optional. The default width is 480, and height is 290.
 //
 // combo: Specifies the create a chart that combines two or more chart types
diff --git a/chart_test.go b/chart_test.go
index 3c80b39..a0f7156 100644
--- a/chart_test.go
+++ b/chart_test.go
@@ -116,7 +116,7 @@ func TestAddChart(t *testing.T) {
 	// Test add chart on not exists worksheet.
 	assert.EqualError(t, f.AddChart("SheetN", "P1", "{}"), "sheet SheetN does not exist")
 
-	assert.NoError(t, f.AddChart("Sheet1", "P1", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"none":true,"show_legend_key":true},"title":{"name":"2D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`))
+	assert.NoError(t, f.AddChart("Sheet1", "P1", `{"type":"col","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"none":true,"show_legend_key":true},"title":{"name":"2D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero","x_axis":{"number_font":{"bold":true,"italic":true,"underline":"dbl","color":"#000000"}},"y_axis":{"number_font":{"bold":false,"italic":false,"underline":"sng","color":"#777777"}}}`))
 	assert.NoError(t, f.AddChart("Sheet1", "X1", `{"type":"colStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"2D Stacked Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`))
 	assert.NoError(t, f.AddChart("Sheet1", "P16", `{"type":"colPercentStacked","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"100% Stacked Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`))
 	assert.NoError(t, f.AddChart("Sheet1", "X16", `{"type":"col3DClustered","series":[{"name":"Sheet1!$A$30","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$30:$D$30"},{"name":"Sheet1!$A$31","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$31:$D$31"},{"name":"Sheet1!$A$32","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$32:$D$32"},{"name":"Sheet1!$A$33","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$33:$D$33"},{"name":"Sheet1!$A$34","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$34:$D$34"},{"name":"Sheet1!$A$35","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$35:$D$35"},{"name":"Sheet1!$A$36","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$36:$D$36"},{"name":"Sheet1!$A$37","categories":"Sheet1!$B$29:$D$29","values":"Sheet1!$B$37:$D$37"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"3D Clustered Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`))
diff --git a/drawing.go b/drawing.go
index 2da2573..974d627 100644
--- a/drawing.go
+++ b/drawing.go
@@ -1017,7 +1017,7 @@ func (f *File) drawPlotAreaCatAx(opts *chartOptions) []*cAxs {
 			MinorTickMark: &attrValString{Val: stringPtr("none")},
 			TickLblPos:    &attrValString{Val: stringPtr("nextTo")},
 			SpPr:          f.drawPlotAreaSpPr(),
-			TxPr:          f.drawPlotAreaTxPr(),
+			TxPr:          f.drawPlotAreaTxPr(&opts.YAxis),
 			CrossAx:       &attrValInt{Val: intPtr(753999904)},
 			Crosses:       &attrValString{Val: stringPtr("autoZero")},
 			Auto:          &attrValBool{Val: boolPtr(true)},
@@ -1071,7 +1071,7 @@ func (f *File) drawPlotAreaValAx(opts *chartOptions) []*cAxs {
 			MinorTickMark: &attrValString{Val: stringPtr("none")},
 			TickLblPos:    &attrValString{Val: stringPtr("nextTo")},
 			SpPr:          f.drawPlotAreaSpPr(),
-			TxPr:          f.drawPlotAreaTxPr(),
+			TxPr:          f.drawPlotAreaTxPr(&opts.XAxis),
 			CrossAx:       &attrValInt{Val: intPtr(754001152)},
 			Crosses:       &attrValString{Val: stringPtr("autoZero")},
 			CrossBetween:  &attrValString{Val: stringPtr(chartValAxCrossBetween[opts.Type])},
@@ -1114,7 +1114,7 @@ func (f *File) drawPlotAreaSerAx(opts *chartOptions) []*cAxs {
 			AxPos:      &attrValString{Val: stringPtr(catAxPos[opts.XAxis.ReverseOrder])},
 			TickLblPos: &attrValString{Val: stringPtr("nextTo")},
 			SpPr:       f.drawPlotAreaSpPr(),
-			TxPr:       f.drawPlotAreaTxPr(),
+			TxPr:       f.drawPlotAreaTxPr(nil),
 			CrossAx:    &attrValInt{Val: intPtr(753999904)},
 		},
 	}
@@ -1140,8 +1140,8 @@ func (f *File) drawPlotAreaSpPr() *cSpPr {
 }
 
 // drawPlotAreaTxPr provides a function to draw the c:txPr element.
-func (f *File) drawPlotAreaTxPr() *cTxPr {
-	return &cTxPr{
+func (f *File) drawPlotAreaTxPr(opts *chartAxisOptions) *cTxPr {
+	cTxPr := &cTxPr{
 		BodyPr: aBodyPr{
 			Rot:              -60000000,
 			SpcFirstLastPara: true,
@@ -1176,6 +1176,18 @@ func (f *File) drawPlotAreaTxPr() *cTxPr {
 			EndParaRPr: &aEndParaRPr{Lang: "en-US"},
 		},
 	}
+	if opts != nil {
+		cTxPr.P.PPr.DefRPr.B = opts.NumFont.Bold
+		cTxPr.P.PPr.DefRPr.I = opts.NumFont.Italic
+		if idx := inStrSlice(supportedDrawingUnderlineTypes, opts.NumFont.Underline, true); idx != -1 {
+			cTxPr.P.PPr.DefRPr.U = supportedDrawingUnderlineTypes[idx]
+		}
+		if opts.NumFont.Color != "" {
+			cTxPr.P.PPr.DefRPr.SolidFill.SchemeClr = nil
+			cTxPr.P.PPr.DefRPr.SolidFill.SrgbClr = &attrValString{Val: stringPtr(strings.ReplaceAll(strings.ToUpper(opts.NumFont.Color), "#", ""))}
+		}
+	}
+	return cTxPr
 }
 
 // drawingParser provides a function to parse drawingXML. In order to solve
diff --git a/file.go b/file.go
index c83d17e..7ce536c 100644
--- a/file.go
+++ b/file.go
@@ -72,7 +72,7 @@ func (f *File) SaveAs(name string, opts ...Options) error {
 		return ErrMaxFilePathLength
 	}
 	f.Path = name
-	if _, ok := supportedContentType[filepath.Ext(f.Path)]; !ok {
+	if _, ok := supportedContentTypes[filepath.Ext(f.Path)]; !ok {
 		return ErrWorkbookFileFormat
 	}
 	file, err := os.OpenFile(filepath.Clean(name), os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.ModePerm)
@@ -112,7 +112,7 @@ func (f *File) WriteTo(w io.Writer, opts ...Options) (int64, error) {
 		f.options = &opts[i]
 	}
 	if len(f.Path) != 0 {
-		contentType, ok := supportedContentType[filepath.Ext(f.Path)]
+		contentType, ok := supportedContentTypes[filepath.Ext(f.Path)]
 		if !ok {
 			return 0, ErrWorkbookFileFormat
 		}
diff --git a/shape.go b/shape.go
index eca354f..e3c6c8b 100644
--- a/shape.go
+++ b/shape.go
@@ -323,27 +323,6 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *shapeOption
 	colIdx := fromCol - 1
 	rowIdx := fromRow - 1
 
-	textUnderlineType := map[string]bool{
-		"none":            true,
-		"words":           true,
-		"sng":             true,
-		"dbl":             true,
-		"heavy":           true,
-		"dotted":          true,
-		"dottedHeavy":     true,
-		"dash":            true,
-		"dashHeavy":       true,
-		"dashLong":        true,
-		"dashLongHeavy":   true,
-		"dotDash":         true,
-		"dotDashHeavy":    true,
-		"dotDotDash":      true,
-		"dotDotDashHeavy": true,
-		"wavy":            true,
-		"wavyHeavy":       true,
-		"wavyDbl":         true,
-	}
-
 	width := int(float64(opts.Width) * opts.Format.XScale)
 	height := int(float64(opts.Height) * opts.Format.YScale)
 
@@ -422,10 +401,9 @@ func (f *File) addDrawingShape(sheet, drawingXML, cell string, opts *shapeOption
 		}
 	}
 	for _, p := range opts.Paragraph {
-		u := p.Font.Underline
-		_, ok := textUnderlineType[u]
-		if !ok {
-			u = "none"
+		u := "none"
+		if idx := inStrSlice(supportedDrawingUnderlineTypes, p.Font.Underline, true); idx != -1 {
+			u = supportedDrawingUnderlineTypes[idx]
 		}
 		text := p.Text
 		if text == "" {
diff --git a/styles.go b/styles.go
index 5299fbd..dc34427 100644
--- a/styles.go
+++ b/styles.go
@@ -2087,7 +2087,6 @@ func (f *File) getFontID(styleSheet *xlsxStyleSheet, style *Style) (fontID int)
 // newFont provides a function to add font style by given cell format
 // settings.
 func (f *File) newFont(style *Style) *xlsxFont {
-	fontUnderlineType := map[string]string{"single": "single", "double": "double"}
 	if style.Font.Size < MinFontSize {
 		style.Font.Size = 11
 	}
@@ -2112,9 +2111,8 @@ func (f *File) newFont(style *Style) *xlsxFont {
 	if style.Font.Strike {
 		fnt.Strike = &attrValBool{Val: &style.Font.Strike}
 	}
-	val, ok := fontUnderlineType[style.Font.Underline]
-	if ok {
-		fnt.U = &attrValString{Val: stringPtr(val)}
+	if idx := inStrSlice(supportedUnderlineTypes, style.Font.Underline, true); idx != -1 {
+		fnt.U = &attrValString{Val: stringPtr(supportedUnderlineTypes[idx])}
 	}
 	return &fnt
 }
@@ -3100,13 +3098,10 @@ func drawCondFmtCellIs(p int, ct string, format *conditionalOptions) *xlsxCfRule
 		DxfID:    &format.Format,
 	}
 	// "between" and "not between" criteria require 2 values.
-	_, ok := map[string]bool{"between": true, "notBetween": true}[ct]
-	if ok {
-		c.Formula = append(c.Formula, format.Minimum)
-		c.Formula = append(c.Formula, format.Maximum)
+	if ct == "between" || ct == "notBetween" {
+		c.Formula = append(c.Formula, []string{format.Minimum, format.Maximum}...)
 	}
-	_, ok = map[string]bool{"equal": true, "notEqual": true, "greaterThan": true, "lessThan": true, "greaterThanOrEqual": true, "lessThanOrEqual": true, "containsText": true, "notContains": true, "beginsWith": true, "endsWith": true}[ct]
-	if ok {
+	if idx := inStrSlice([]string{"equal", "notEqual", "greaterThan", "lessThan", "greaterThanOrEqual", "lessThanOrEqual", "containsText", "notContains", "beginsWith", "endsWith"}, ct, true); idx != -1 {
 		c.Formula = append(c.Formula, format.Value)
 	}
 	return c
@@ -3124,8 +3119,7 @@ func drawCondFmtTop10(p int, ct string, format *conditionalOptions) *xlsxCfRule
 		DxfID:    &format.Format,
 		Percent:  format.Percent,
 	}
-	rank, err := strconv.Atoi(format.Value)
-	if err == nil {
+	if rank, err := strconv.Atoi(format.Value); err == nil {
 		c.Rank = rank
 	}
 	return c
diff --git a/table.go b/table.go
index f7cac20..112882c 100644
--- a/table.go
+++ b/table.go
@@ -516,7 +516,7 @@ func (f *File) parseFilterTokens(expression string, tokens []string) ([]int, str
 			}
 		}
 	}
-	// if the string token contains an Excel match character then change the
+	// If the string token contains an Excel match character then change the
 	// operator type to indicate a non "simple" equality.
 	re, _ = regexp.Match("[*?]", []byte(token))
 	if operator == 2 && re {
diff --git a/xmlChart.go b/xmlChart.go
index 9024770..27a790e 100644
--- a/xmlChart.go
+++ b/xmlChart.go
@@ -521,31 +521,26 @@ type cPageMargins struct {
 
 // chartAxisOptions directly maps the format settings of the chart axis.
 type chartAxisOptions struct {
-	None                bool     `json:"none"`
-	Crossing            string   `json:"crossing"`
-	MajorGridlines      bool     `json:"major_grid_lines"`
-	MinorGridlines      bool     `json:"minor_grid_lines"`
-	MajorTickMark       string   `json:"major_tick_mark"`
-	MinorTickMark       string   `json:"minor_tick_mark"`
-	MinorUnitType       string   `json:"minor_unit_type"`
-	MajorUnit           float64  `json:"major_unit"`
-	MajorUnitType       string   `json:"major_unit_type"`
-	TickLabelSkip       int      `json:"tick_label_skip"`
-	DisplayUnits        string   `json:"display_units"`
-	DisplayUnitsVisible bool     `json:"display_units_visible"`
-	DateAxis            bool     `json:"date_axis"`
-	ReverseOrder        bool     `json:"reverse_order"`
-	Maximum             *float64 `json:"maximum"`
-	Minimum             *float64 `json:"minimum"`
-	NumFormat           string   `json:"num_format"`
-	NumFont             struct {
-		Color     string `json:"color"`
-		Bold      bool   `json:"bold"`
-		Italic    bool   `json:"italic"`
-		Underline bool   `json:"underline"`
-	} `json:"num_font"`
-	LogBase    float64       `json:"logbase"`
-	NameLayout layoutOptions `json:"name_layout"`
+	None                bool          `json:"none"`
+	Crossing            string        `json:"crossing"`
+	MajorGridlines      bool          `json:"major_grid_lines"`
+	MinorGridlines      bool          `json:"minor_grid_lines"`
+	MajorTickMark       string        `json:"major_tick_mark"`
+	MinorTickMark       string        `json:"minor_tick_mark"`
+	MinorUnitType       string        `json:"minor_unit_type"`
+	MajorUnit           float64       `json:"major_unit"`
+	MajorUnitType       string        `json:"major_unit_type"`
+	TickLabelSkip       int           `json:"tick_label_skip"`
+	DisplayUnits        string        `json:"display_units"`
+	DisplayUnitsVisible bool          `json:"display_units_visible"`
+	DateAxis            bool          `json:"date_axis"`
+	ReverseOrder        bool          `json:"reverse_order"`
+	Maximum             *float64      `json:"maximum"`
+	Minimum             *float64      `json:"minimum"`
+	NumFormat           string        `json:"number_format"`
+	NumFont             Font          `json:"number_font"`
+	LogBase             float64       `json:"logbase"`
+	NameLayout          layoutOptions `json:"name_layout"`
 }
 
 // chartDimensionOptions directly maps the dimension of the chart.
diff --git a/xmlDrawing.go b/xmlDrawing.go
index 6a2f79d..b52e449 100644
--- a/xmlDrawing.go
+++ b/xmlDrawing.go
@@ -144,8 +144,8 @@ const (
 // supportedImageTypes defined supported image types.
 var supportedImageTypes = map[string]string{".gif": ".gif", ".jpg": ".jpeg", ".jpeg": ".jpeg", ".png": ".png", ".tif": ".tiff", ".tiff": ".tiff", ".emf": ".emf", ".wmf": ".wmf", ".emz": ".emz", ".wmz": ".wmz"}
 
-// supportedContentType defined supported file format types.
-var supportedContentType = map[string]string{
+// supportedContentTypes defined supported file format types.
+var supportedContentTypes = map[string]string{
 	".xlam": ContentTypeAddinMacro,
 	".xlsm": ContentTypeMacro,
 	".xlsx": ContentTypeSheetML,
@@ -153,6 +153,16 @@ var supportedContentType = map[string]string{
 	".xltx": ContentTypeTemplate,
 }
 
+// supportedUnderlineTypes defined supported underline types.
+var supportedUnderlineTypes = []string{"none", "single", "double"}
+
+// supportedDrawingUnderlineTypes defined supported underline types in drawing
+// markup language.
+var supportedDrawingUnderlineTypes = []string{
+	"none", "words", "sng", "dbl", "heavy", "dotted", "dottedHeavy", "dash", "dashHeavy", "dashLong", "dashLongHeavy", "dotDash", "dotDashHeavy", "dotDotDash", "dotDotDashHeavy", "wavy", "wavyHeavy",
+	"wavyDbl",
+}
+
 // xlsxCNvPr directly maps the cNvPr (Non-Visual Drawing Properties). This
 // element specifies non-visual canvas properties. This allows for additional
 // information that does not affect the appearance of the picture to be stored.
-- 
cgit v1.2.1