xlsxwriter 0.2.1.pre.2 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -3
  3. data/ext/xlsxwriter/chart.c +20 -2
  4. data/ext/xlsxwriter/extconf.rb +8 -8
  5. data/ext/xlsxwriter/libxlsxwriter/License.txt +24 -2
  6. data/ext/xlsxwriter/libxlsxwriter/Makefile +46 -12
  7. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/app.h +1 -1
  8. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chart.h +196 -30
  9. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/chartsheet.h +3 -3
  10. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/comment.h +76 -0
  11. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/common.h +24 -5
  12. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/content_types.h +5 -1
  13. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/core.h +1 -1
  14. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/custom.h +1 -1
  15. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/drawing.h +6 -17
  16. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/format.h +20 -6
  17. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/hash_table.h +1 -1
  18. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/packager.h +3 -1
  19. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/relationships.h +1 -1
  20. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/shared_strings.h +1 -1
  21. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/styles.h +11 -5
  22. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/theme.h +1 -1
  23. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/third_party/md5.h +43 -0
  24. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/utility.h +42 -3
  25. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/vml.h +55 -0
  26. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/workbook.h +83 -18
  27. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/worksheet.h +1519 -109
  28. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter/xmlwriter.h +4 -2
  29. data/ext/xlsxwriter/libxlsxwriter/include/xlsxwriter.h +3 -2
  30. data/ext/xlsxwriter/libxlsxwriter/src/Makefile +25 -7
  31. data/ext/xlsxwriter/libxlsxwriter/src/app.c +1 -1
  32. data/ext/xlsxwriter/libxlsxwriter/src/chart.c +332 -48
  33. data/ext/xlsxwriter/libxlsxwriter/src/chartsheet.c +20 -19
  34. data/ext/xlsxwriter/libxlsxwriter/src/comment.c +443 -0
  35. data/ext/xlsxwriter/libxlsxwriter/src/content_types.c +20 -1
  36. data/ext/xlsxwriter/libxlsxwriter/src/core.c +2 -2
  37. data/ext/xlsxwriter/libxlsxwriter/src/custom.c +1 -1
  38. data/ext/xlsxwriter/libxlsxwriter/src/drawing.c +58 -20
  39. data/ext/xlsxwriter/libxlsxwriter/src/format.c +98 -25
  40. data/ext/xlsxwriter/libxlsxwriter/src/hash_table.c +1 -1
  41. data/ext/xlsxwriter/libxlsxwriter/src/packager.c +269 -12
  42. data/ext/xlsxwriter/libxlsxwriter/src/relationships.c +1 -1
  43. data/ext/xlsxwriter/libxlsxwriter/src/shared_strings.c +2 -4
  44. data/ext/xlsxwriter/libxlsxwriter/src/styles.c +334 -48
  45. data/ext/xlsxwriter/libxlsxwriter/src/theme.c +1 -1
  46. data/ext/xlsxwriter/libxlsxwriter/src/utility.c +71 -8
  47. data/ext/xlsxwriter/libxlsxwriter/src/vml.c +1032 -0
  48. data/ext/xlsxwriter/libxlsxwriter/src/workbook.c +343 -27
  49. data/ext/xlsxwriter/libxlsxwriter/src/worksheet.c +3759 -478
  50. data/ext/xlsxwriter/libxlsxwriter/src/xmlwriter.c +81 -2
  51. data/ext/xlsxwriter/libxlsxwriter/third_party/md5/Makefile +42 -0
  52. data/ext/xlsxwriter/libxlsxwriter/third_party/md5/md5.c +291 -0
  53. data/ext/xlsxwriter/libxlsxwriter/third_party/md5/md5.h +43 -0
  54. data/ext/xlsxwriter/shared_strings.c +65 -0
  55. data/ext/xlsxwriter/shared_strings.h +15 -0
  56. data/ext/xlsxwriter/workbook.c +56 -1
  57. data/ext/xlsxwriter/worksheet.c +31 -2
  58. data/ext/xlsxwriter/worksheet.h +1 -0
  59. data/ext/xlsxwriter/xlsxwriter.c +2 -0
  60. data/lib/xlsxwriter/rich_string.rb +0 -2
  61. data/lib/xlsxwriter/version.rb +1 -1
  62. data/lib/xlsxwriter/worksheet.rb +2 -2
  63. data/test/{run-test.rb → run_test.rb} +3 -3
  64. data/test/support/chart_test.rb +3 -3
  65. data/test/support/with_xlsx_file.rb +4 -2
  66. data/test/support/xlsx_comparable.rb +40 -26
  67. data/test/test_array_formula.rb +42 -0
  68. data/test/test_autofilter.rb +72 -0
  69. data/test/{test-chart-area.rb → test_chart_area.rb} +2 -2
  70. data/test/{test-chart-axis.rb → test_chart_axis.rb} +16 -16
  71. data/test/test_chart_bar.rb +382 -0
  72. data/test/test_chart_blank.rb +27 -0
  73. data/test/{test-chart-column.rb → test_chart_column.rb} +2 -2
  74. data/test/{test-chart-doughnut.rb → test_chart_doughnut.rb} +2 -2
  75. data/test/{test-chart-legend.rb → test_chart_legend.rb} +2 -2
  76. data/test/{test-chart-pie.rb → test_chart_pie.rb} +2 -2
  77. data/test/{test-chart-scatter.rb → test_chart_scatter.rb} +3 -4
  78. data/test/{test-chart-size.rb → test_chart_size.rb} +2 -2
  79. data/test/{test-chart-title.rb → test_chart_title.rb} +3 -3
  80. data/test/{test-chartsheet.rb → test_chartsheet.rb} +2 -2
  81. data/test/{test-data.rb → test_data.rb} +1 -1
  82. data/test/{test-data-validation.rb → test_data_validation.rb} +23 -24
  83. data/test/{test-default-row.rb → test_default_row.rb} +1 -1
  84. data/test/{test-defined-name.rb → test_defined_name.rb} +12 -12
  85. data/test/{test-escapes.rb → test_escapes.rb} +5 -2
  86. data/test/{test-fit-to-pages.rb → test_fit_to_pages.rb} +6 -6
  87. data/test/{test-formatting.rb → test_formatting.rb} +10 -10
  88. data/test/{test-gridlines.rb → test_gridlines.rb} +3 -3
  89. data/test/{test-hyperlink.rb → test_hyperlink.rb} +22 -11
  90. data/test/{test-image.rb → test_image.rb} +6 -4
  91. data/test/{test-macro.rb → test_macro.rb} +1 -1
  92. data/test/{test-merge-range.rb → test_merge_range.rb} +1 -1
  93. data/test/{test-misc.rb → test_misc.rb} +2 -2
  94. data/test/{test-optimize.rb → test_optimize.rb} +2 -4
  95. data/test/{test-outline.rb → test_outline.rb} +14 -14
  96. data/test/{test-page-breaks.rb → test_page_breaks.rb} +2 -2
  97. data/test/{test-page-setup.rb → test_page_setup.rb} +2 -2
  98. data/test/{test-panes.rb → test_panes.rb} +1 -1
  99. data/test/{test-print-area.rb → test_print_area.rb} +3 -3
  100. data/test/{test-print-options.rb → test_print_options.rb} +7 -7
  101. data/test/{test-print-scale.rb → test_print_scale.rb} +2 -2
  102. data/test/{test-properties.rb → test_properties.rb} +2 -2
  103. data/test/{test-protect.rb → test_protect.rb} +3 -3
  104. data/test/{test-repeat.rb → test_repeat.rb} +3 -3
  105. data/test/{test-rich-string.rb → test_rich_string.rb} +5 -9
  106. data/test/{test-row-col-format.rb → test_row_col_format.rb} +1 -1
  107. data/test/{test-ruby-worksheet.rb → test_ruby_worksheet.rb} +2 -2
  108. data/test/{test-set-selection.rb → test_set_selection.rb} +2 -2
  109. data/test/{test-set-start-page.rb → test_set_start_page.rb} +2 -2
  110. data/test/{test-simple.rb → test_simple.rb} +10 -10
  111. data/test/{test-types.rb → test_types.rb} +1 -1
  112. data/test/{xlsx-func-testcase.rb → xlsx_func_testcase.rb} +1 -0
  113. metadata +132 -106
  114. data/test/test-array-formula.rb +0 -35
  115. data/test/test-autofilter.rb +0 -72
  116. data/test/test-chart-bar.rb +0 -74
  117. /data/test/{test-errors.rb → test_errors.rb} +0 -0
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Used in conjunction with the libxlsxwriter library.
5
5
  *
6
- * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * Copyright 2014-2020, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
7
  *
8
8
  */
9
9
 
@@ -82,6 +82,26 @@ _chart_free_font(lxw_chart_font *font)
82
82
  free(font);
83
83
  }
84
84
 
85
+ STATIC void
86
+ _chart_free_data_labels(lxw_chart_series *series)
87
+ {
88
+ uint16_t index;
89
+
90
+ for (index = 0; index < series->data_label_count; index++) {
91
+ lxw_chart_custom_label *data_label = &series->data_labels[index];
92
+
93
+ free(data_label->value);
94
+ _chart_free_range(data_label->range);
95
+ _chart_free_font(data_label->font);
96
+ free(data_label->line);
97
+ free(data_label->fill);
98
+ free(data_label->pattern);
99
+ }
100
+
101
+ series->data_label_count = 0;
102
+ free(series->data_labels);
103
+ }
104
+
85
105
  /*
86
106
  * Free a series object.
87
107
  */
@@ -96,6 +116,10 @@ _chart_series_free(lxw_chart_series *series)
96
116
  free(series->fill);
97
117
  free(series->pattern);
98
118
  free(series->label_num_format);
119
+ free(series->label_line);
120
+ free(series->label_fill);
121
+ free(series->label_pattern);
122
+
99
123
  _chart_free_font(series->label_font);
100
124
 
101
125
  if (series->marker) {
@@ -109,6 +133,7 @@ _chart_series_free(lxw_chart_series *series)
109
133
  _chart_free_range(series->values);
110
134
  _chart_free_range(series->title.range);
111
135
  _chart_free_points(series);
136
+ _chart_free_data_labels(series);
112
137
 
113
138
  if (series->x_error_bars) {
114
139
  free(series->x_error_bars->line);
@@ -331,11 +356,6 @@ _chart_convert_font_args(lxw_chart_font *user_font)
331
356
  if (font->rotation)
332
357
  font->rotation = font->rotation * 60000;
333
358
 
334
- if (font->color) {
335
- font->color = lxw_format_check_color(font->color);
336
- font->has_color = LXW_TRUE;
337
- }
338
-
339
359
  return font;
340
360
  }
341
361
 
@@ -360,11 +380,6 @@ _chart_convert_line_args(lxw_chart_line *user_line)
360
380
  line->dash_type = user_line->dash_type;
361
381
  line->transparency = user_line->transparency;
362
382
 
363
- if (line->color) {
364
- line->color = lxw_format_check_color(line->color);
365
- line->has_color = LXW_TRUE;
366
- }
367
-
368
383
  if (line->transparency > 100)
369
384
  line->transparency = 0;
370
385
 
@@ -390,11 +405,6 @@ _chart_convert_fill_args(lxw_chart_fill *user_fill)
390
405
  fill->none = user_fill->none;
391
406
  fill->transparency = user_fill->transparency;
392
407
 
393
- if (fill->color) {
394
- fill->color = lxw_format_check_color(fill->color);
395
- fill->has_color = LXW_TRUE;
396
- }
397
-
398
408
  if (fill->transparency > 100)
399
409
  fill->transparency = 0;
400
410
 
@@ -430,17 +440,9 @@ _chart_convert_pattern_args(lxw_chart_pattern *user_pattern)
430
440
  pattern->bg_color = user_pattern->bg_color;
431
441
  pattern->type = user_pattern->type;
432
442
 
433
- pattern->fg_color = lxw_format_check_color(pattern->fg_color);
434
- pattern->has_fg_color = LXW_TRUE;
435
-
436
- if (pattern->bg_color) {
437
- pattern->bg_color = lxw_format_check_color(pattern->bg_color);
438
- pattern->has_bg_color = LXW_TRUE;
439
- }
440
- else {
443
+ if (!pattern->bg_color) {
441
444
  /* Default background color in Excel is white, when unspecified. */
442
445
  pattern->bg_color = LXW_COLOR_WHITE;
443
- pattern->has_bg_color = LXW_TRUE;
444
446
  }
445
447
 
446
448
  return pattern;
@@ -857,7 +859,7 @@ _chart_write_a_def_rpr(lxw_chart *self, lxw_chart_font *font)
857
859
  LXW_INIT_ATTRIBUTES();
858
860
 
859
861
  if (font) {
860
- has_color = font->color || font->has_color;
862
+ has_color = !!font->color;
861
863
  has_latin = font->name || font->pitch_family || font->charset;
862
864
  use_font_default = !(has_color || has_latin || font->baseline == -1);
863
865
 
@@ -929,7 +931,7 @@ _chart_write_a_r_pr(lxw_chart *self, lxw_chart_font *font)
929
931
  LXW_PUSH_ATTRIBUTES_STR("lang", "en-US");
930
932
 
931
933
  if (font) {
932
- has_color = font->color || font->has_color;
934
+ has_color = !!font->color;
933
935
  has_latin = font->name || font->pitch_family || font->charset;
934
936
  use_font_default = !(has_color || has_latin || font->baseline == -1);
935
937
 
@@ -1090,12 +1092,14 @@ _chart_write_a_p_pie(lxw_chart *self, lxw_chart_font *font)
1090
1092
  * Write the <a:p> element.
1091
1093
  */
1092
1094
  STATIC void
1093
- _chart_write_a_p_rich(lxw_chart *self, char *name, lxw_chart_font *font)
1095
+ _chart_write_a_p_rich(lxw_chart *self, char *name, lxw_chart_font *font,
1096
+ uint8_t ignore_rich_pr)
1094
1097
  {
1095
1098
  lxw_xml_start_tag(self->file, "a:p", NULL);
1096
1099
 
1097
1100
  /* Write the a:pPr element. */
1098
- _chart_write_a_p_pr_rich(self, font);
1101
+ if (!ignore_rich_pr)
1102
+ _chart_write_a_p_pr_rich(self, font);
1099
1103
 
1100
1104
  /* Write the a:r element. */
1101
1105
  _chart_write_a_r(self, name, font);
@@ -1127,11 +1131,22 @@ _chart_write_a_body_pr(lxw_chart *self, int32_t rotation,
1127
1131
  if (rotation == 0 && is_horizontal)
1128
1132
  rotation = -5400000;
1129
1133
 
1130
- if (rotation)
1131
- LXW_PUSH_ATTRIBUTES_INT("rot", rotation);
1132
-
1133
- if (is_horizontal)
1134
- LXW_PUSH_ATTRIBUTES_STR("vert", "horz");
1134
+ if (rotation) {
1135
+ if (rotation == 16200000) {
1136
+ /* 270 deg/stacked angle. */
1137
+ LXW_PUSH_ATTRIBUTES_STR("rot", "0");
1138
+ LXW_PUSH_ATTRIBUTES_STR("vert", "wordArtVert");
1139
+ }
1140
+ else if (rotation == 16260000) {
1141
+ /* 271 deg/East Asian vertical. */
1142
+ LXW_PUSH_ATTRIBUTES_STR("rot", "0");
1143
+ LXW_PUSH_ATTRIBUTES_STR("vert", "eaVert");
1144
+ }
1145
+ else {
1146
+ LXW_PUSH_ATTRIBUTES_INT("rot", rotation);
1147
+ LXW_PUSH_ATTRIBUTES_STR("vert", "horz");
1148
+ }
1149
+ }
1135
1150
 
1136
1151
  lxw_xml_empty_tag(self->file, "a:bodyPr", &attributes);
1137
1152
 
@@ -1466,8 +1481,8 @@ _chart_write_axis_font(lxw_chart *self, lxw_chart_font *font)
1466
1481
  * Write the <c:rich> element.
1467
1482
  */
1468
1483
  STATIC void
1469
- _chart_write_rich(lxw_chart *self, char *name, uint8_t is_horizontal,
1470
- lxw_chart_font *font)
1484
+ _chart_write_rich(lxw_chart *self, char *name, lxw_chart_font *font,
1485
+ uint8_t is_horizontal, uint8_t ignore_rich_pr)
1471
1486
  {
1472
1487
  int32_t rotation = 0;
1473
1488
 
@@ -1483,7 +1498,7 @@ _chart_write_rich(lxw_chart *self, char *name, uint8_t is_horizontal,
1483
1498
  _chart_write_a_lst_style(self);
1484
1499
 
1485
1500
  /* Write the a:p element. */
1486
- _chart_write_a_p_rich(self, name, font);
1501
+ _chart_write_a_p_rich(self, name, font, ignore_rich_pr);
1487
1502
 
1488
1503
  lxw_xml_end_tag(self->file, "c:rich");
1489
1504
  }
@@ -1499,7 +1514,7 @@ _chart_write_tx_rich(lxw_chart *self, char *name, uint8_t is_horizontal,
1499
1514
  lxw_xml_start_tag(self->file, "c:tx", NULL);
1500
1515
 
1501
1516
  /* Write the c:rich element. */
1502
- _chart_write_rich(self, name, is_horizontal, font);
1517
+ _chart_write_rich(self, name, font, is_horizontal, LXW_FALSE);
1503
1518
 
1504
1519
  lxw_xml_end_tag(self->file, "c:tx");
1505
1520
  }
@@ -1668,7 +1683,7 @@ _chart_write_a_ln(lxw_chart *self, lxw_chart_line *line)
1668
1683
  /* Write the a:noFill element. */
1669
1684
  _chart_write_a_no_fill(self);
1670
1685
  }
1671
- else if (line->has_color) {
1686
+ else if (line->color) {
1672
1687
  /* Write the a:solidFill element. */
1673
1688
  _chart_write_a_solid_fill(self, line->color, line->transparency);
1674
1689
  }
@@ -1824,10 +1839,10 @@ _chart_write_a_patt_fill(lxw_chart *self, lxw_chart_pattern *pattern)
1824
1839
 
1825
1840
  lxw_xml_start_tag(self->file, "a:pattFill", &attributes);
1826
1841
 
1827
- if (pattern->has_fg_color)
1842
+ if (pattern->fg_color)
1828
1843
  _chart_write_a_fg_clr(self, pattern->fg_color);
1829
1844
 
1830
- if (pattern->has_bg_color)
1845
+ if (pattern->bg_color)
1831
1846
  _chart_write_a_bg_clr(self, pattern->bg_color);
1832
1847
 
1833
1848
  lxw_xml_end_tag(self->file, "a:pattFill");
@@ -2268,6 +2283,133 @@ _chart_write_label_num_fmt(lxw_chart *self, char *format)
2268
2283
  LXW_FREE_ATTRIBUTES();
2269
2284
  }
2270
2285
 
2286
+ /*
2287
+ * Write parts of the <c:dLbl> elements where only formatting is changed.
2288
+ */
2289
+ STATIC void
2290
+ _chart_write_custom_label_format_only(lxw_chart *self,
2291
+ lxw_chart_custom_label *data_label)
2292
+ {
2293
+ if (data_label->line || data_label->fill || data_label->pattern) {
2294
+ _chart_write_sp_pr(self, data_label->line, data_label->fill,
2295
+ data_label->pattern);
2296
+ _chart_write_tx_pr(self, LXW_FALSE, data_label->font);
2297
+ }
2298
+ else if (data_label->font) {
2299
+ lxw_xml_empty_tag(self->file, "c:spPr", NULL);
2300
+ _chart_write_tx_pr(self, LXW_FALSE, data_label->font);
2301
+ }
2302
+ }
2303
+
2304
+ /*
2305
+ * Write parts of the <c:dLbl> elements for formula custom labels.
2306
+ */
2307
+ STATIC void
2308
+ _chart_write_custom_label_formula(lxw_chart *self, lxw_chart_series *series,
2309
+ lxw_chart_custom_label *data_label)
2310
+ {
2311
+ lxw_xml_empty_tag(self->file, "c:layout", NULL);
2312
+ lxw_xml_start_tag(self->file, "c:tx", NULL);
2313
+
2314
+ _chart_write_str_ref(self, data_label->range);
2315
+
2316
+ lxw_xml_end_tag(self->file, "c:tx");
2317
+
2318
+ _chart_write_custom_label_format_only(self, data_label);
2319
+
2320
+ /* Write the c:showVal element. */
2321
+ if (series->show_labels_value)
2322
+ _chart_write_show_val(self);
2323
+
2324
+ /* Write the c:showCatName element. */
2325
+ if (series->show_labels_category)
2326
+ _chart_write_show_cat_name(self);
2327
+
2328
+ /* Write the c:showSerName element. */
2329
+ if (series->show_labels_name)
2330
+ _chart_write_show_ser_name(self);
2331
+
2332
+ }
2333
+
2334
+ /*
2335
+ * Write parts of the <c:dLbl> elements for string custom labels.
2336
+ */
2337
+ STATIC void
2338
+ _chart_write_custom_label_str(lxw_chart *self, lxw_chart_series *series,
2339
+ lxw_chart_custom_label *data_label)
2340
+ {
2341
+ uint8_t ignore_rich_pr = LXW_TRUE;
2342
+
2343
+ if (data_label->line || data_label->fill || data_label->pattern)
2344
+ ignore_rich_pr = LXW_FALSE;
2345
+
2346
+ lxw_xml_empty_tag(self->file, "c:layout", NULL);
2347
+ lxw_xml_start_tag(self->file, "c:tx", NULL);
2348
+
2349
+ /* Write the c:rich element. */
2350
+ _chart_write_rich(self, data_label->value, data_label->font,
2351
+ LXW_FALSE, ignore_rich_pr);
2352
+
2353
+ lxw_xml_end_tag(self->file, "c:tx");
2354
+
2355
+ /* Write the c:spPr element. */
2356
+ _chart_write_sp_pr(self, data_label->line, data_label->fill,
2357
+ data_label->pattern);
2358
+
2359
+ /* Write the c:showVal element. */
2360
+ if (series->show_labels_value)
2361
+ _chart_write_show_val(self);
2362
+
2363
+ /* Write the c:showCatName element. */
2364
+ if (series->show_labels_category)
2365
+ _chart_write_show_cat_name(self);
2366
+
2367
+ /* Write the c:showSerName element. */
2368
+ if (series->show_labels_name)
2369
+ _chart_write_show_ser_name(self);
2370
+
2371
+ }
2372
+
2373
+ /*
2374
+ * Write the <c:dLbl> elements for custom labels.
2375
+ */
2376
+ STATIC void
2377
+ _chart_write_custom_labels(lxw_chart *self, lxw_chart_series *series)
2378
+ {
2379
+ uint16_t index = 0;
2380
+
2381
+ for (index = 0; index < series->data_label_count; index++) {
2382
+ lxw_chart_custom_label *data_label = &series->data_labels[index];
2383
+
2384
+ if (!data_label->value && !data_label->range && !data_label->hide
2385
+ && !data_label->font) {
2386
+
2387
+ continue;
2388
+ }
2389
+
2390
+ lxw_xml_start_tag(self->file, "c:dLbl", NULL);
2391
+
2392
+ /* Write the c:idx element. */
2393
+ _chart_write_idx(self, index);
2394
+
2395
+ if (data_label->hide) {
2396
+ /* Write the c:delete element. */
2397
+ _chart_write_delete(self);
2398
+ }
2399
+ else if (data_label->value) {
2400
+ _chart_write_custom_label_str(self, series, data_label);
2401
+ }
2402
+ else if (data_label->range) {
2403
+ _chart_write_custom_label_formula(self, series, data_label);
2404
+ }
2405
+ else if (data_label->font) {
2406
+ _chart_write_custom_label_format_only(self, data_label);
2407
+ }
2408
+
2409
+ lxw_xml_end_tag(self->file, "c:dLbl");
2410
+ }
2411
+ }
2412
+
2271
2413
  /*
2272
2414
  * Write the <c:dLbls> element.
2273
2415
  */
@@ -2279,10 +2421,17 @@ _chart_write_d_lbls(lxw_chart *self, lxw_chart_series *series)
2279
2421
 
2280
2422
  lxw_xml_start_tag(self->file, "c:dLbls", NULL);
2281
2423
 
2424
+ if (series->data_labels)
2425
+ _chart_write_custom_labels(self, series);
2426
+
2282
2427
  /* Write the c:numFmt element. */
2283
2428
  if (series->label_num_format)
2284
2429
  _chart_write_label_num_fmt(self, series->label_num_format);
2285
2430
 
2431
+ /* Write the c:spPr element. */
2432
+ _chart_write_sp_pr(self, series->label_line, series->label_fill,
2433
+ series->label_pattern);
2434
+
2286
2435
  if (series->label_font)
2287
2436
  _chart_write_tx_pr(self, LXW_FALSE, series->label_font);
2288
2437
 
@@ -3569,7 +3718,7 @@ _chart_write_legend_entry(lxw_chart *self, uint16_t index)
3569
3718
  /* Write the c:idx element. */
3570
3719
  _chart_write_idx(self, self->delete_series[index]);
3571
3720
 
3572
- /* Write the c:delete element. */
3721
+ /* Write the c:dst_label element. */
3573
3722
  _chart_write_delete(self);
3574
3723
 
3575
3724
  lxw_xml_end_tag(self->file, "c:legendEntry");
@@ -4504,8 +4653,7 @@ _chart_write_scatter_chart(lxw_chart *self)
4504
4653
  LXW_TRUE,
4505
4654
  2.25,
4506
4655
  LXW_CHART_LINE_DASH_SOLID,
4507
- 0,
4508
- LXW_FALSE
4656
+ 0
4509
4657
  };
4510
4658
  series->line = _chart_convert_line_args(&line);
4511
4659
  }
@@ -4797,7 +4945,7 @@ _chart_initialize_doughnut_chart(lxw_chart *self)
4797
4945
  * Initialize a line chart.
4798
4946
  */
4799
4947
  STATIC void
4800
- _chart_initialize_line_chart(lxw_chart *self)
4948
+ _chart_initialize_line_chart(lxw_chart *self, uint8_t type)
4801
4949
  {
4802
4950
  self->chart_group = LXW_CHART_LINE;
4803
4951
  _chart_set_default_marker_type(self, LXW_CHART_MARKER_NONE);
@@ -4806,6 +4954,17 @@ _chart_initialize_line_chart(lxw_chart *self)
4806
4954
  self->y_axis->is_value = LXW_TRUE;
4807
4955
  self->default_label_position = LXW_CHART_LABEL_POSITION_RIGHT;
4808
4956
 
4957
+ if (type == LXW_CHART_LINE_STACKED) {
4958
+ self->grouping = LXW_GROUPING_STACKED;
4959
+ self->subtype = LXW_CHART_SUBTYPE_STACKED;
4960
+ }
4961
+
4962
+ if (type == LXW_CHART_LINE_STACKED_PERCENT) {
4963
+ self->grouping = LXW_GROUPING_PERCENTSTACKED;
4964
+ _chart_axis_set_default_num_format(self->y_axis, "0%");
4965
+ self->subtype = LXW_CHART_SUBTYPE_STACKED;
4966
+ }
4967
+
4809
4968
  /* Initialize the function pointers for this chart type. */
4810
4969
  self->write_chart_type = _chart_write_line_chart;
4811
4970
  self->write_plot_area = _chart_write_plot_area;
@@ -4900,7 +5059,9 @@ _chart_initialize(lxw_chart *self, uint8_t type)
4900
5059
  break;
4901
5060
 
4902
5061
  case LXW_CHART_LINE:
4903
- _chart_initialize_line_chart(self);
5062
+ case LXW_CHART_LINE_STACKED:
5063
+ case LXW_CHART_LINE_STACKED_PERCENT:
5064
+ _chart_initialize_line_chart(self, type);
4904
5065
  break;
4905
5066
 
4906
5067
  case LXW_CHART_PIE:
@@ -4999,7 +5160,7 @@ lxw_chart_add_data_cache(lxw_series_range *range, uint8_t *data,
4999
5160
  }
5000
5161
 
5001
5162
  /*
5002
- * Insert an image into the worksheet.
5163
+ * Add a series to the chart.
5003
5164
  */
5004
5165
  lxw_chart_series *
5005
5166
  chart_add_series(lxw_chart *self, const char *categories, const char *values)
@@ -5306,7 +5467,7 @@ chart_series_set_marker_pattern(lxw_chart_series *series,
5306
5467
  }
5307
5468
 
5308
5469
  /*
5309
- * Store the horizontal page breaks on a worksheet.
5470
+ * Store the points for a chart.
5310
5471
  */
5311
5472
  lxw_error
5312
5473
  chart_series_set_points(lxw_chart_series *series, lxw_chart_point *points[])
@@ -5375,6 +5536,83 @@ chart_series_set_labels_options(lxw_chart_series *series, uint8_t show_name,
5375
5536
  series->show_labels_value = show_value;
5376
5537
  }
5377
5538
 
5539
+ /*
5540
+ * Store the custom data_labels for a chart.
5541
+ */
5542
+ lxw_error
5543
+ chart_series_set_labels_custom(lxw_chart_series *series,
5544
+ lxw_chart_data_label *data_labels[])
5545
+ {
5546
+ uint16_t i = 0;
5547
+ uint16_t data_label_count = 0;
5548
+
5549
+ if (data_labels == NULL)
5550
+ return LXW_ERROR_NULL_PARAMETER_IGNORED;
5551
+
5552
+ while (data_labels[data_label_count])
5553
+ data_label_count++;
5554
+
5555
+ if (data_label_count == 0)
5556
+ return LXW_ERROR_NULL_PARAMETER_IGNORED;
5557
+
5558
+ series->has_labels = LXW_TRUE;
5559
+
5560
+ /* Set the Value label type if no other type is set. */
5561
+ if (!series->show_labels_name && !series->show_labels_category
5562
+ && !series->show_labels_value) {
5563
+ series->show_labels_value = LXW_TRUE;
5564
+ }
5565
+
5566
+ /* Free any existing resource. */
5567
+ _chart_free_data_labels(series);
5568
+
5569
+ series->data_labels = calloc(data_label_count,
5570
+ sizeof(lxw_chart_custom_label));
5571
+ RETURN_ON_MEM_ERROR(series->data_labels, LXW_ERROR_MEMORY_MALLOC_FAILED);
5572
+
5573
+ /* Copy the user data into the array of new structs. The struct types
5574
+ * are different since the internal version has more fields. */
5575
+ for (i = 0; i < data_label_count; i++) {
5576
+ lxw_chart_data_label *user_label = data_labels[i];
5577
+ lxw_chart_custom_label *data_label = &series->data_labels[i];
5578
+ char *src_value = user_label->value;
5579
+
5580
+ data_label->hide = user_label->hide;
5581
+ data_label->font = _chart_convert_font_args(user_label->font);
5582
+ data_label->line = _chart_convert_line_args(user_label->line);
5583
+ data_label->fill = _chart_convert_fill_args(user_label->fill);
5584
+ data_label->pattern =
5585
+ _chart_convert_pattern_args(user_label->pattern);
5586
+
5587
+ if (src_value) {
5588
+ if (*src_value == '=') {
5589
+ /* The value is a formula. Handle like other chart ranges. */
5590
+ data_label->range = calloc(1, sizeof(lxw_series_range));
5591
+ GOTO_LABEL_ON_MEM_ERROR(data_label->range, mem_error);
5592
+
5593
+ data_label->range->formula = lxw_strdup(src_value + 1);
5594
+
5595
+ /* Add the formula to the data cache to allow value to be looked
5596
+ * up and filled in when the file is closed. */
5597
+ if (_chart_init_data_cache(data_label->range) != LXW_NO_ERROR)
5598
+ goto mem_error;
5599
+ }
5600
+ else {
5601
+ /* The value is a simple string. */
5602
+ data_label->value = lxw_strdup(src_value);
5603
+ }
5604
+ }
5605
+ }
5606
+
5607
+ series->data_label_count = data_label_count;
5608
+
5609
+ return LXW_NO_ERROR;
5610
+
5611
+ mem_error:
5612
+ _chart_free_data_labels(series);
5613
+ return LXW_ERROR_MEMORY_MALLOC_FAILED;
5614
+ }
5615
+
5378
5616
  /*
5379
5617
  * Set the data labels separator for a series.
5380
5618
  */
@@ -5459,6 +5697,52 @@ chart_series_set_labels_font(lxw_chart_series *series, lxw_chart_font *font)
5459
5697
  series->label_font = _chart_convert_font_args(font);
5460
5698
  }
5461
5699
 
5700
+ /*
5701
+ * Set a line type for a series data labels.
5702
+ */
5703
+ void
5704
+ chart_series_set_labels_line(lxw_chart_series *series, lxw_chart_line *line)
5705
+ {
5706
+ if (!line)
5707
+ return;
5708
+
5709
+ /* Free any previously allocated resource. */
5710
+ free(series->label_line);
5711
+
5712
+ series->label_line = _chart_convert_line_args(line);
5713
+ }
5714
+
5715
+ /*
5716
+ * Set a fill type for a series data labels.
5717
+ */
5718
+ void
5719
+ chart_series_set_labels_fill(lxw_chart_series *series, lxw_chart_fill *fill)
5720
+ {
5721
+ if (!fill)
5722
+ return;
5723
+
5724
+ /* Free any previously allocated resource. */
5725
+ free(series->label_fill);
5726
+
5727
+ series->label_fill = _chart_convert_fill_args(fill);
5728
+ }
5729
+
5730
+ /*
5731
+ * Set a pattern type for a series data labels.
5732
+ */
5733
+ void
5734
+ chart_series_set_labels_pattern(lxw_chart_series *series,
5735
+ lxw_chart_pattern *pattern)
5736
+ {
5737
+ if (!pattern)
5738
+ return;
5739
+
5740
+ /* Free any previously allocated resource. */
5741
+ free(series->label_pattern);
5742
+
5743
+ series->label_pattern = _chart_convert_pattern_args(pattern);
5744
+ }
5745
+
5462
5746
  /*
5463
5747
  * Set the trendline for a chart series.
5464
5748
  */
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Used in conjunction with the libxlsxwriter library.
5
5
  *
6
- * Copyright 2014-2019, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
6
+ * Copyright 2014-2020, John McNamara, jmcnamara@cpan.org. See LICENSE.txt.
7
7
  *
8
8
  */
9
9
 
@@ -225,9 +225,9 @@ lxw_chartsheet_assemble_xml_file(lxw_chartsheet *self)
225
225
  */
226
226
  lxw_error
227
227
  chartsheet_set_chart_opt(lxw_chartsheet *self,
228
- lxw_chart *chart, lxw_image_options *user_options)
228
+ lxw_chart *chart, lxw_chart_options *user_options)
229
229
  {
230
- lxw_image_options *options;
230
+ lxw_object_properties *object_props;
231
231
  lxw_chart_series *series;
232
232
 
233
233
  if (!chart) {
@@ -260,32 +260,33 @@ chartsheet_set_chart_opt(lxw_chartsheet *self,
260
260
  }
261
261
  }
262
262
 
263
- /* Create a new object to hold the chart image options. */
264
- options = calloc(1, sizeof(lxw_image_options));
265
- RETURN_ON_MEM_ERROR(options, LXW_ERROR_MEMORY_MALLOC_FAILED);
263
+ /* Create a new object to hold the chart image properties. */
264
+ object_props = calloc(1, sizeof(lxw_object_properties));
265
+ RETURN_ON_MEM_ERROR(object_props, LXW_ERROR_MEMORY_MALLOC_FAILED);
266
266
 
267
267
  if (user_options) {
268
- options->x_offset = user_options->x_offset;
269
- options->y_offset = user_options->y_offset;
270
- options->x_scale = user_options->x_scale;
271
- options->y_scale = user_options->y_scale;
268
+ object_props->x_offset = user_options->x_offset;
269
+ object_props->y_offset = user_options->y_offset;
270
+ object_props->x_scale = user_options->x_scale;
271
+ object_props->y_scale = user_options->y_scale;
272
272
  }
273
273
 
274
274
  /* TODO. Read defaults from chart. */
275
- options->width = 480;
276
- options->height = 288;
275
+ object_props->width = 480;
276
+ object_props->height = 288;
277
277
 
278
- if (!options->x_scale)
279
- options->x_scale = 1;
278
+ if (!object_props->x_scale)
279
+ object_props->x_scale = 1;
280
280
 
281
- if (!options->y_scale)
282
- options->y_scale = 1;
281
+ if (!object_props->y_scale)
282
+ object_props->y_scale = 1;
283
283
 
284
284
  /* Store chart references so they can be ordered in the workbook. */
285
- options->chart = chart;
285
+ object_props->chart = chart;
286
286
 
287
287
  /* Store the chart data in the embedded worksheet. */
288
- STAILQ_INSERT_TAIL(self->worksheet->chart_data, options, list_pointers);
288
+ STAILQ_INSERT_TAIL(self->worksheet->chart_data, object_props,
289
+ list_pointers);
289
290
 
290
291
  chart->in_use = LXW_TRUE;
291
292
  chart->is_chartsheet = LXW_TRUE;
@@ -385,7 +386,7 @@ void
385
386
  chartsheet_protect(lxw_chartsheet *self, const char *password,
386
387
  lxw_protection *options)
387
388
  {
388
- struct lxw_protection *protect = &self->protection;
389
+ struct lxw_protection_obj *protect = &self->protection;
389
390
 
390
391
  /* Copy any user parameters to the internal structure. */
391
392
  if (options) {