styles.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  1. /*****************************************************************************
  2. * styles - A library for creating Excel XLSX styles files.
  3. *
  4. * Used in conjunction with the libxlsxwriter library.
  5. *
  6. * Copyright 2014-2018, John McNamara, [email protected]. See LICENSE.txt.
  7. *
  8. */
  9. #include "xlsxwriter/xmlwriter.h"
  10. #include "xlsxwriter/styles.h"
  11. #include "xlsxwriter/utility.h"
  12. /*
  13. * Forward declarations.
  14. */
  15. /*****************************************************************************
  16. *
  17. * Private functions.
  18. *
  19. ****************************************************************************/
  20. /*
  21. * Create a new styles object.
  22. */
  23. lxw_styles *
  24. lxw_styles_new()
  25. {
  26. lxw_styles *styles = calloc(1, sizeof(lxw_styles));
  27. GOTO_LABEL_ON_MEM_ERROR(styles, mem_error);
  28. styles->xf_formats = calloc(1, sizeof(struct lxw_formats));
  29. GOTO_LABEL_ON_MEM_ERROR(styles->xf_formats, mem_error);
  30. STAILQ_INIT(styles->xf_formats);
  31. return styles;
  32. mem_error:
  33. lxw_styles_free(styles);
  34. return NULL;
  35. }
  36. /*
  37. * Free a styles object.
  38. */
  39. void
  40. lxw_styles_free(lxw_styles *styles)
  41. {
  42. lxw_format *format;
  43. if (!styles)
  44. return;
  45. /* Free the formats in the styles. */
  46. if (styles->xf_formats) {
  47. while (!STAILQ_EMPTY(styles->xf_formats)) {
  48. format = STAILQ_FIRST(styles->xf_formats);
  49. STAILQ_REMOVE_HEAD(styles->xf_formats, list_pointers);
  50. free(format);
  51. }
  52. free(styles->xf_formats);
  53. }
  54. free(styles);
  55. }
  56. /*****************************************************************************
  57. *
  58. * XML functions.
  59. *
  60. ****************************************************************************/
  61. /*
  62. * Write the XML declaration.
  63. */
  64. STATIC void
  65. _styles_xml_declaration(lxw_styles *self)
  66. {
  67. lxw_xml_declaration(self->file);
  68. }
  69. /*
  70. * Write the <styleSheet> element.
  71. */
  72. STATIC void
  73. _write_style_sheet(lxw_styles *self)
  74. {
  75. struct xml_attribute_list attributes;
  76. struct xml_attribute *attribute;
  77. LXW_INIT_ATTRIBUTES();
  78. LXW_PUSH_ATTRIBUTES_STR("xmlns",
  79. "http://schemas.openxmlformats.org/spreadsheetml/2006/main");
  80. lxw_xml_start_tag(self->file, "styleSheet", &attributes);
  81. LXW_FREE_ATTRIBUTES();
  82. }
  83. /*
  84. * Write the <numFmt> element.
  85. */
  86. STATIC void
  87. _write_num_fmt(lxw_styles *self, uint16_t num_fmt_id, char *format_code)
  88. {
  89. struct xml_attribute_list attributes;
  90. struct xml_attribute *attribute;
  91. LXW_INIT_ATTRIBUTES();
  92. LXW_PUSH_ATTRIBUTES_INT("numFmtId", num_fmt_id);
  93. LXW_PUSH_ATTRIBUTES_STR("formatCode", format_code);
  94. lxw_xml_empty_tag(self->file, "numFmt", &attributes);
  95. LXW_FREE_ATTRIBUTES();
  96. }
  97. /*
  98. * Write the <numFmts> element.
  99. */
  100. STATIC void
  101. _write_num_fmts(lxw_styles *self)
  102. {
  103. struct xml_attribute_list attributes;
  104. struct xml_attribute *attribute;
  105. lxw_format *format;
  106. if (!self->num_format_count)
  107. return;
  108. LXW_INIT_ATTRIBUTES();
  109. LXW_PUSH_ATTRIBUTES_INT("count", self->num_format_count);
  110. lxw_xml_start_tag(self->file, "numFmts", &attributes);
  111. /* Write the numFmts elements. */
  112. STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
  113. /* Ignore built-in number formats, i.e., < 164. */
  114. if (format->num_format_index < 164)
  115. continue;
  116. _write_num_fmt(self, format->num_format_index, format->num_format);
  117. }
  118. lxw_xml_end_tag(self->file, "numFmts");
  119. LXW_FREE_ATTRIBUTES();
  120. }
  121. /*
  122. * Write the <sz> element.
  123. */
  124. STATIC void
  125. _write_font_size(lxw_styles *self, double font_size)
  126. {
  127. struct xml_attribute_list attributes;
  128. struct xml_attribute *attribute;
  129. LXW_INIT_ATTRIBUTES();
  130. LXW_PUSH_ATTRIBUTES_DBL("val", font_size);
  131. lxw_xml_empty_tag(self->file, "sz", &attributes);
  132. LXW_FREE_ATTRIBUTES();
  133. }
  134. /*
  135. * Write the <color> element for themes.
  136. */
  137. STATIC void
  138. _write_font_color_theme(lxw_styles *self, uint8_t theme)
  139. {
  140. struct xml_attribute_list attributes;
  141. struct xml_attribute *attribute;
  142. LXW_INIT_ATTRIBUTES();
  143. LXW_PUSH_ATTRIBUTES_INT("theme", theme);
  144. lxw_xml_empty_tag(self->file, "color", &attributes);
  145. LXW_FREE_ATTRIBUTES();
  146. }
  147. /*
  148. * Write the <color> element for RGB colors.
  149. */
  150. STATIC void
  151. _write_font_color_rgb(lxw_styles *self, int32_t rgb)
  152. {
  153. struct xml_attribute_list attributes;
  154. struct xml_attribute *attribute;
  155. char rgb_str[LXW_ATTR_32];
  156. lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", rgb & LXW_COLOR_MASK);
  157. LXW_INIT_ATTRIBUTES();
  158. LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
  159. lxw_xml_empty_tag(self->file, "color", &attributes);
  160. LXW_FREE_ATTRIBUTES();
  161. }
  162. /*
  163. * Write the <name> element.
  164. */
  165. STATIC void
  166. _write_font_name(lxw_styles *self, const char *font_name)
  167. {
  168. struct xml_attribute_list attributes;
  169. struct xml_attribute *attribute;
  170. LXW_INIT_ATTRIBUTES();
  171. if (*font_name)
  172. LXW_PUSH_ATTRIBUTES_STR("val", font_name);
  173. else
  174. LXW_PUSH_ATTRIBUTES_STR("val", LXW_DEFAULT_FONT_NAME);
  175. lxw_xml_empty_tag(self->file, "name", &attributes);
  176. LXW_FREE_ATTRIBUTES();
  177. }
  178. /*
  179. * Write the <family> element.
  180. */
  181. STATIC void
  182. _write_font_family(lxw_styles *self, uint8_t font_family)
  183. {
  184. struct xml_attribute_list attributes;
  185. struct xml_attribute *attribute;
  186. LXW_INIT_ATTRIBUTES();
  187. LXW_PUSH_ATTRIBUTES_INT("val", font_family);
  188. lxw_xml_empty_tag(self->file, "family", &attributes);
  189. LXW_FREE_ATTRIBUTES();
  190. }
  191. /*
  192. * Write the <scheme> element.
  193. */
  194. STATIC void
  195. _write_font_scheme(lxw_styles *self, const char *font_scheme)
  196. {
  197. struct xml_attribute_list attributes;
  198. struct xml_attribute *attribute;
  199. LXW_INIT_ATTRIBUTES();
  200. if (*font_scheme)
  201. LXW_PUSH_ATTRIBUTES_STR("val", font_scheme);
  202. else
  203. LXW_PUSH_ATTRIBUTES_STR("val", "minor");
  204. lxw_xml_empty_tag(self->file, "scheme", &attributes);
  205. LXW_FREE_ATTRIBUTES();
  206. }
  207. /*
  208. * Write the underline font element.
  209. */
  210. STATIC void
  211. _write_font_underline(lxw_styles *self, uint8_t underline)
  212. {
  213. struct xml_attribute_list attributes;
  214. struct xml_attribute *attribute;
  215. LXW_INIT_ATTRIBUTES();
  216. /* Handle the underline variants. */
  217. if (underline == LXW_UNDERLINE_DOUBLE)
  218. LXW_PUSH_ATTRIBUTES_STR("val", "double");
  219. else if (underline == LXW_UNDERLINE_SINGLE_ACCOUNTING)
  220. LXW_PUSH_ATTRIBUTES_STR("val", "singleAccounting");
  221. else if (underline == LXW_UNDERLINE_DOUBLE_ACCOUNTING)
  222. LXW_PUSH_ATTRIBUTES_STR("val", "doubleAccounting");
  223. /* Default to single underline. */
  224. lxw_xml_empty_tag(self->file, "u", &attributes);
  225. LXW_FREE_ATTRIBUTES();
  226. }
  227. /*
  228. * Write the <vertAlign> font sub-element.
  229. */
  230. STATIC void
  231. _write_vert_align(lxw_styles *self, const char *align)
  232. {
  233. struct xml_attribute_list attributes;
  234. struct xml_attribute *attribute;
  235. LXW_INIT_ATTRIBUTES();
  236. LXW_PUSH_ATTRIBUTES_STR("val", align);
  237. lxw_xml_empty_tag(self->file, "vertAlign", &attributes);
  238. LXW_FREE_ATTRIBUTES();
  239. }
  240. /*
  241. * Write the <font> element.
  242. */
  243. STATIC void
  244. _write_font(lxw_styles *self, lxw_format *format)
  245. {
  246. lxw_xml_start_tag(self->file, "font", NULL);
  247. if (format->bold)
  248. lxw_xml_empty_tag(self->file, "b", NULL);
  249. if (format->italic)
  250. lxw_xml_empty_tag(self->file, "i", NULL);
  251. if (format->font_strikeout)
  252. lxw_xml_empty_tag(self->file, "strike", NULL);
  253. if (format->font_outline)
  254. lxw_xml_empty_tag(self->file, "outline", NULL);
  255. if (format->font_shadow)
  256. lxw_xml_empty_tag(self->file, "shadow", NULL);
  257. if (format->underline)
  258. _write_font_underline(self, format->underline);
  259. if (format->font_script == LXW_FONT_SUPERSCRIPT)
  260. _write_vert_align(self, "superscript");
  261. if (format->font_script == LXW_FONT_SUBSCRIPT)
  262. _write_vert_align(self, "subscript");
  263. if (format->font_size > 0.0)
  264. _write_font_size(self, format->font_size);
  265. if (format->theme)
  266. _write_font_color_theme(self, format->theme);
  267. else if (format->font_color != LXW_COLOR_UNSET)
  268. _write_font_color_rgb(self, format->font_color);
  269. else
  270. _write_font_color_theme(self, LXW_DEFAULT_FONT_THEME);
  271. _write_font_name(self, format->font_name);
  272. _write_font_family(self, format->font_family);
  273. /* Only write the scheme element for the default font type if it
  274. * is a hyperlink. */
  275. if ((!*format->font_name
  276. || strcmp(LXW_DEFAULT_FONT_NAME, format->font_name) == 0)
  277. && !format->hyperlink) {
  278. _write_font_scheme(self, format->font_scheme);
  279. }
  280. lxw_xml_end_tag(self->file, "font");
  281. }
  282. /*
  283. * Write the <fonts> element.
  284. */
  285. STATIC void
  286. _write_fonts(lxw_styles *self)
  287. {
  288. struct xml_attribute_list attributes;
  289. struct xml_attribute *attribute;
  290. lxw_format *format;
  291. LXW_INIT_ATTRIBUTES();
  292. LXW_PUSH_ATTRIBUTES_INT("count", self->font_count);
  293. lxw_xml_start_tag(self->file, "fonts", &attributes);
  294. STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
  295. if (format->has_font)
  296. _write_font(self, format);
  297. }
  298. lxw_xml_end_tag(self->file, "fonts");
  299. LXW_FREE_ATTRIBUTES();
  300. }
  301. /*
  302. * Write the default <fill> element.
  303. */
  304. STATIC void
  305. _write_default_fill(lxw_styles *self, const char *pattern)
  306. {
  307. struct xml_attribute_list attributes;
  308. struct xml_attribute *attribute;
  309. LXW_INIT_ATTRIBUTES();
  310. LXW_PUSH_ATTRIBUTES_STR("patternType", pattern);
  311. lxw_xml_start_tag(self->file, "fill", NULL);
  312. lxw_xml_empty_tag(self->file, "patternFill", &attributes);
  313. lxw_xml_end_tag(self->file, "fill");
  314. LXW_FREE_ATTRIBUTES();
  315. }
  316. /*
  317. * Write the <fgColor> element.
  318. */
  319. STATIC void
  320. _write_fg_color(lxw_styles *self, lxw_color_t color)
  321. {
  322. struct xml_attribute_list attributes;
  323. struct xml_attribute *attribute;
  324. char rgb_str[LXW_ATTR_32];
  325. LXW_INIT_ATTRIBUTES();
  326. lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", color & LXW_COLOR_MASK);
  327. LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
  328. lxw_xml_empty_tag(self->file, "fgColor", &attributes);
  329. LXW_FREE_ATTRIBUTES();
  330. }
  331. /*
  332. * Write the <bgColor> element.
  333. */
  334. STATIC void
  335. _write_bg_color(lxw_styles *self, lxw_color_t color)
  336. {
  337. struct xml_attribute_list attributes;
  338. struct xml_attribute *attribute;
  339. char rgb_str[LXW_ATTR_32];
  340. LXW_INIT_ATTRIBUTES();
  341. if (color == LXW_COLOR_UNSET) {
  342. LXW_PUSH_ATTRIBUTES_STR("indexed", "64");
  343. }
  344. else {
  345. lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", color & LXW_COLOR_MASK);
  346. LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
  347. }
  348. lxw_xml_empty_tag(self->file, "bgColor", &attributes);
  349. LXW_FREE_ATTRIBUTES();
  350. }
  351. /*
  352. * Write the <fill> element.
  353. */
  354. STATIC void
  355. _write_fill(lxw_styles *self, lxw_format *format)
  356. {
  357. struct xml_attribute_list attributes;
  358. struct xml_attribute *attribute;
  359. uint8_t pattern = format->pattern;
  360. lxw_color_t bg_color = format->bg_color;
  361. lxw_color_t fg_color = format->fg_color;
  362. char *patterns[] = {
  363. "none",
  364. "solid",
  365. "mediumGray",
  366. "darkGray",
  367. "lightGray",
  368. "darkHorizontal",
  369. "darkVertical",
  370. "darkDown",
  371. "darkUp",
  372. "darkGrid",
  373. "darkTrellis",
  374. "lightHorizontal",
  375. "lightVertical",
  376. "lightDown",
  377. "lightUp",
  378. "lightGrid",
  379. "lightTrellis",
  380. "gray125",
  381. "gray0625",
  382. };
  383. LXW_INIT_ATTRIBUTES();
  384. lxw_xml_start_tag(self->file, "fill", NULL);
  385. if (pattern)
  386. LXW_PUSH_ATTRIBUTES_STR("patternType", patterns[pattern]);
  387. lxw_xml_start_tag(self->file, "patternFill", &attributes);
  388. if (fg_color != LXW_COLOR_UNSET)
  389. _write_fg_color(self, fg_color);
  390. _write_bg_color(self, bg_color);
  391. lxw_xml_end_tag(self->file, "patternFill");
  392. lxw_xml_end_tag(self->file, "fill");
  393. LXW_FREE_ATTRIBUTES();
  394. }
  395. /*
  396. * Write the <fills> element.
  397. */
  398. STATIC void
  399. _write_fills(lxw_styles *self)
  400. {
  401. struct xml_attribute_list attributes;
  402. struct xml_attribute *attribute;
  403. lxw_format *format;
  404. LXW_INIT_ATTRIBUTES();
  405. LXW_PUSH_ATTRIBUTES_INT("count", self->fill_count);
  406. lxw_xml_start_tag(self->file, "fills", &attributes);
  407. /* Write the default fills. */
  408. _write_default_fill(self, "none");
  409. _write_default_fill(self, "gray125");
  410. STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
  411. if (format->has_fill)
  412. _write_fill(self, format);
  413. }
  414. lxw_xml_end_tag(self->file, "fills");
  415. LXW_FREE_ATTRIBUTES();
  416. }
  417. /*
  418. * Write the border <color> element.
  419. */
  420. STATIC void
  421. _write_border_color(lxw_styles *self, lxw_color_t color)
  422. {
  423. struct xml_attribute_list attributes;
  424. struct xml_attribute *attribute;
  425. char rgb_str[LXW_ATTR_32];
  426. LXW_INIT_ATTRIBUTES();
  427. if (color != LXW_COLOR_UNSET) {
  428. lxw_snprintf(rgb_str, LXW_ATTR_32, "FF%06X", color & LXW_COLOR_MASK);
  429. LXW_PUSH_ATTRIBUTES_STR("rgb", rgb_str);
  430. }
  431. else {
  432. LXW_PUSH_ATTRIBUTES_STR("auto", "1");
  433. }
  434. lxw_xml_empty_tag(self->file, "color", &attributes);
  435. LXW_FREE_ATTRIBUTES();
  436. }
  437. /*
  438. * Write the <border> sub elements such as <right>, <top>, etc.
  439. */
  440. STATIC void
  441. _write_sub_border(lxw_styles *self, const char *type, uint8_t style,
  442. lxw_color_t color)
  443. {
  444. struct xml_attribute_list attributes;
  445. struct xml_attribute *attribute;
  446. char *border_styles[] = {
  447. "none",
  448. "thin",
  449. "medium",
  450. "dashed",
  451. "dotted",
  452. "thick",
  453. "double",
  454. "hair",
  455. "mediumDashed",
  456. "dashDot",
  457. "mediumDashDot",
  458. "dashDotDot",
  459. "mediumDashDotDot",
  460. "slantDashDot",
  461. };
  462. if (!style) {
  463. lxw_xml_empty_tag(self->file, type, NULL);
  464. return;
  465. }
  466. LXW_INIT_ATTRIBUTES();
  467. LXW_PUSH_ATTRIBUTES_STR("style", border_styles[style]);
  468. lxw_xml_start_tag(self->file, type, &attributes);
  469. _write_border_color(self, color);
  470. lxw_xml_end_tag(self->file, type);
  471. LXW_FREE_ATTRIBUTES();
  472. }
  473. /*
  474. * Write the <border> element.
  475. */
  476. STATIC void
  477. _write_border(lxw_styles *self, lxw_format *format)
  478. {
  479. struct xml_attribute_list attributes;
  480. struct xml_attribute *attribute;
  481. LXW_INIT_ATTRIBUTES();
  482. /* Add attributes for diagonal borders. */
  483. if (format->diag_type == LXW_DIAGONAL_BORDER_UP) {
  484. LXW_PUSH_ATTRIBUTES_STR("diagonalUp", "1");
  485. }
  486. else if (format->diag_type == LXW_DIAGONAL_BORDER_DOWN) {
  487. LXW_PUSH_ATTRIBUTES_STR("diagonalDown", "1");
  488. }
  489. else if (format->diag_type == LXW_DIAGONAL_BORDER_UP_DOWN) {
  490. LXW_PUSH_ATTRIBUTES_STR("diagonalUp", "1");
  491. LXW_PUSH_ATTRIBUTES_STR("diagonalDown", "1");
  492. }
  493. /* Ensure that a default diag border is set if the diag type is set. */
  494. if (format->diag_type && !format->diag_border) {
  495. format->diag_border = 1;
  496. }
  497. /* Write the start border tag. */
  498. lxw_xml_start_tag(self->file, "border", &attributes);
  499. /* Write the <border> sub elements. */
  500. _write_sub_border(self, "left", format->left, format->left_color);
  501. _write_sub_border(self, "right", format->right, format->right_color);
  502. _write_sub_border(self, "top", format->top, format->top_color);
  503. _write_sub_border(self, "bottom", format->bottom, format->bottom_color);
  504. _write_sub_border(self,
  505. "diagonal", format->diag_border, format->diag_color);
  506. lxw_xml_end_tag(self->file, "border");
  507. LXW_FREE_ATTRIBUTES();
  508. }
  509. /*
  510. * Write the <borders> element.
  511. */
  512. STATIC void
  513. _write_borders(lxw_styles *self)
  514. {
  515. struct xml_attribute_list attributes;
  516. struct xml_attribute *attribute;
  517. lxw_format *format;
  518. LXW_INIT_ATTRIBUTES();
  519. LXW_PUSH_ATTRIBUTES_INT("count", self->border_count);
  520. lxw_xml_start_tag(self->file, "borders", &attributes);
  521. STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
  522. if (format->has_border)
  523. _write_border(self, format);
  524. }
  525. lxw_xml_end_tag(self->file, "borders");
  526. LXW_FREE_ATTRIBUTES();
  527. }
  528. /*
  529. * Write the <xf> element for styles.
  530. */
  531. STATIC void
  532. _write_style_xf(lxw_styles *self)
  533. {
  534. struct xml_attribute_list attributes;
  535. struct xml_attribute *attribute;
  536. LXW_INIT_ATTRIBUTES();
  537. LXW_PUSH_ATTRIBUTES_STR("numFmtId", "0");
  538. LXW_PUSH_ATTRIBUTES_STR("fontId", "0");
  539. LXW_PUSH_ATTRIBUTES_STR("fillId", "0");
  540. LXW_PUSH_ATTRIBUTES_STR("borderId", "0");
  541. lxw_xml_empty_tag(self->file, "xf", &attributes);
  542. LXW_FREE_ATTRIBUTES();
  543. }
  544. /*
  545. * Write the <cellStyleXfs> element.
  546. */
  547. STATIC void
  548. _write_cell_style_xfs(lxw_styles *self)
  549. {
  550. struct xml_attribute_list attributes;
  551. struct xml_attribute *attribute;
  552. LXW_INIT_ATTRIBUTES();
  553. LXW_PUSH_ATTRIBUTES_STR("count", "1");
  554. lxw_xml_start_tag(self->file, "cellStyleXfs", &attributes);
  555. _write_style_xf(self);
  556. lxw_xml_end_tag(self->file, "cellStyleXfs");
  557. LXW_FREE_ATTRIBUTES();
  558. }
  559. /*
  560. * Check if a format struct has alignment properties set and the
  561. * "applyAlignment" attribute should be set.
  562. */
  563. STATIC uint8_t
  564. _apply_alignment(lxw_format *format)
  565. {
  566. return format->text_h_align != LXW_ALIGN_NONE
  567. || format->text_v_align != LXW_ALIGN_NONE
  568. || format->indent != 0
  569. || format->rotation != 0
  570. || format->text_wrap != 0
  571. || format->shrink != 0 || format->reading_order != 0;
  572. }
  573. /*
  574. * Check if a format struct has alignment properties set apart from the
  575. * LXW_ALIGN_VERTICAL_BOTTOM which Excel treats as a default.
  576. */
  577. STATIC uint8_t
  578. _has_alignment(lxw_format *format)
  579. {
  580. return format->text_h_align != LXW_ALIGN_NONE
  581. || !(format->text_v_align == LXW_ALIGN_NONE ||
  582. format->text_v_align == LXW_ALIGN_VERTICAL_BOTTOM)
  583. || format->indent != 0
  584. || format->rotation != 0
  585. || format->text_wrap != 0
  586. || format->shrink != 0 || format->reading_order != 0;
  587. }
  588. /*
  589. * Write the <alignment> element.
  590. */
  591. STATIC void
  592. _write_alignment(lxw_styles *self, lxw_format *format)
  593. {
  594. struct xml_attribute_list attributes;
  595. struct xml_attribute *attribute;
  596. int16_t rotation = format->rotation;
  597. LXW_INIT_ATTRIBUTES();
  598. /* Indent is only allowed for horizontal left, right and distributed. */
  599. /* If it is defined for any other alignment or no alignment has been */
  600. /* set then default to left alignment. */
  601. if (format->indent
  602. && format->text_h_align != LXW_ALIGN_LEFT
  603. && format->text_h_align != LXW_ALIGN_RIGHT
  604. && format->text_h_align != LXW_ALIGN_DISTRIBUTED) {
  605. format->text_h_align = LXW_ALIGN_LEFT;
  606. }
  607. /* Check for properties that are mutually exclusive. */
  608. if (format->text_wrap)
  609. format->shrink = 0;
  610. if (format->text_h_align == LXW_ALIGN_FILL)
  611. format->shrink = 0;
  612. if (format->text_h_align == LXW_ALIGN_JUSTIFY)
  613. format->shrink = 0;
  614. if (format->text_h_align == LXW_ALIGN_DISTRIBUTED)
  615. format->shrink = 0;
  616. if (format->text_h_align != LXW_ALIGN_DISTRIBUTED)
  617. format->just_distrib = 0;
  618. if (format->indent)
  619. format->just_distrib = 0;
  620. if (format->text_h_align == LXW_ALIGN_LEFT)
  621. LXW_PUSH_ATTRIBUTES_STR("horizontal", "left");
  622. if (format->text_h_align == LXW_ALIGN_CENTER)
  623. LXW_PUSH_ATTRIBUTES_STR("horizontal", "center");
  624. if (format->text_h_align == LXW_ALIGN_RIGHT)
  625. LXW_PUSH_ATTRIBUTES_STR("horizontal", "right");
  626. if (format->text_h_align == LXW_ALIGN_FILL)
  627. LXW_PUSH_ATTRIBUTES_STR("horizontal", "fill");
  628. if (format->text_h_align == LXW_ALIGN_JUSTIFY)
  629. LXW_PUSH_ATTRIBUTES_STR("horizontal", "justify");
  630. if (format->text_h_align == LXW_ALIGN_CENTER_ACROSS)
  631. LXW_PUSH_ATTRIBUTES_STR("horizontal", "centerContinuous");
  632. if (format->text_h_align == LXW_ALIGN_DISTRIBUTED)
  633. LXW_PUSH_ATTRIBUTES_STR("horizontal", "distributed");
  634. if (format->just_distrib)
  635. LXW_PUSH_ATTRIBUTES_STR("justifyLastLine", "1");
  636. if (format->text_v_align == LXW_ALIGN_VERTICAL_TOP)
  637. LXW_PUSH_ATTRIBUTES_STR("vertical", "top");
  638. if (format->text_v_align == LXW_ALIGN_VERTICAL_CENTER)
  639. LXW_PUSH_ATTRIBUTES_STR("vertical", "center");
  640. if (format->text_v_align == LXW_ALIGN_VERTICAL_JUSTIFY)
  641. LXW_PUSH_ATTRIBUTES_STR("vertical", "justify");
  642. if (format->text_v_align == LXW_ALIGN_VERTICAL_DISTRIBUTED)
  643. LXW_PUSH_ATTRIBUTES_STR("vertical", "distributed");
  644. if (format->indent)
  645. LXW_PUSH_ATTRIBUTES_INT("indent", format->indent);
  646. /* Map rotation to Excel values. */
  647. if (rotation) {
  648. if (rotation == 270)
  649. rotation = 255;
  650. else if (rotation < 0)
  651. rotation = -rotation + 90;
  652. LXW_PUSH_ATTRIBUTES_INT("textRotation", rotation);
  653. }
  654. if (format->text_wrap)
  655. LXW_PUSH_ATTRIBUTES_STR("wrapText", "1");
  656. if (format->shrink)
  657. LXW_PUSH_ATTRIBUTES_STR("shrinkToFit", "1");
  658. if (format->reading_order == 1)
  659. LXW_PUSH_ATTRIBUTES_STR("readingOrder", "1");
  660. if (format->reading_order == 2)
  661. LXW_PUSH_ATTRIBUTES_STR("readingOrder", "2");
  662. if (!STAILQ_EMPTY(&attributes))
  663. lxw_xml_empty_tag(self->file, "alignment", &attributes);
  664. LXW_FREE_ATTRIBUTES();
  665. }
  666. /*
  667. * Write the <protection> element.
  668. */
  669. STATIC void
  670. _write_protection(lxw_styles *self, lxw_format *format)
  671. {
  672. struct xml_attribute_list attributes;
  673. struct xml_attribute *attribute;
  674. LXW_INIT_ATTRIBUTES();
  675. if (!format->locked)
  676. LXW_PUSH_ATTRIBUTES_STR("locked", "0");
  677. if (format->hidden)
  678. LXW_PUSH_ATTRIBUTES_STR("hidden", "1");
  679. lxw_xml_empty_tag(self->file, "protection", &attributes);
  680. LXW_FREE_ATTRIBUTES();
  681. }
  682. /*
  683. * Write the <xf> element.
  684. */
  685. STATIC void
  686. _write_xf(lxw_styles *self, lxw_format *format)
  687. {
  688. struct xml_attribute_list attributes;
  689. struct xml_attribute *attribute;
  690. uint8_t has_protection = (!format->locked) | format->hidden;
  691. uint8_t has_alignment = _has_alignment(format);
  692. uint8_t apply_alignment = _apply_alignment(format);
  693. LXW_INIT_ATTRIBUTES();
  694. LXW_PUSH_ATTRIBUTES_INT("numFmtId", format->num_format_index);
  695. LXW_PUSH_ATTRIBUTES_INT("fontId", format->font_index);
  696. LXW_PUSH_ATTRIBUTES_INT("fillId", format->fill_index);
  697. LXW_PUSH_ATTRIBUTES_INT("borderId", format->border_index);
  698. LXW_PUSH_ATTRIBUTES_STR("xfId", "0");
  699. if (format->num_format_index > 0)
  700. LXW_PUSH_ATTRIBUTES_STR("applyNumberFormat", "1");
  701. /* Add applyFont attribute if XF format uses a font element. */
  702. if (format->font_index > 0)
  703. LXW_PUSH_ATTRIBUTES_STR("applyFont", "1");
  704. /* Add applyFill attribute if XF format uses a fill element. */
  705. if (format->fill_index > 0)
  706. LXW_PUSH_ATTRIBUTES_STR("applyFill", "1");
  707. /* Add applyBorder attribute if XF format uses a border element. */
  708. if (format->border_index > 0)
  709. LXW_PUSH_ATTRIBUTES_STR("applyBorder", "1");
  710. /* We can also have applyAlignment without a sub-element. */
  711. if (apply_alignment)
  712. LXW_PUSH_ATTRIBUTES_STR("applyAlignment", "1");
  713. if (has_protection)
  714. LXW_PUSH_ATTRIBUTES_STR("applyProtection", "1");
  715. /* Write XF with sub-elements if required. */
  716. if (has_alignment || has_protection) {
  717. lxw_xml_start_tag(self->file, "xf", &attributes);
  718. if (has_alignment)
  719. _write_alignment(self, format);
  720. if (has_protection)
  721. _write_protection(self, format);
  722. lxw_xml_end_tag(self->file, "xf");
  723. }
  724. else {
  725. lxw_xml_empty_tag(self->file, "xf", &attributes);
  726. }
  727. LXW_FREE_ATTRIBUTES();
  728. }
  729. /*
  730. * Write the <cellXfs> element.
  731. */
  732. STATIC void
  733. _write_cell_xfs(lxw_styles *self)
  734. {
  735. struct xml_attribute_list attributes;
  736. struct xml_attribute *attribute;
  737. lxw_format *format;
  738. LXW_INIT_ATTRIBUTES();
  739. LXW_PUSH_ATTRIBUTES_INT("count", self->xf_count);
  740. lxw_xml_start_tag(self->file, "cellXfs", &attributes);
  741. STAILQ_FOREACH(format, self->xf_formats, list_pointers) {
  742. _write_xf(self, format);
  743. }
  744. lxw_xml_end_tag(self->file, "cellXfs");
  745. LXW_FREE_ATTRIBUTES();
  746. }
  747. /*
  748. * Write the <cellStyle> element.
  749. */
  750. STATIC void
  751. _write_cell_style(lxw_styles *self)
  752. {
  753. struct xml_attribute_list attributes;
  754. struct xml_attribute *attribute;
  755. LXW_INIT_ATTRIBUTES();
  756. LXW_PUSH_ATTRIBUTES_STR("name", "Normal");
  757. LXW_PUSH_ATTRIBUTES_STR("xfId", "0");
  758. LXW_PUSH_ATTRIBUTES_STR("builtinId", "0");
  759. lxw_xml_empty_tag(self->file, "cellStyle", &attributes);
  760. LXW_FREE_ATTRIBUTES();
  761. }
  762. /*
  763. * Write the <cellStyles> element.
  764. */
  765. STATIC void
  766. _write_cell_styles(lxw_styles *self)
  767. {
  768. struct xml_attribute_list attributes;
  769. struct xml_attribute *attribute;
  770. LXW_INIT_ATTRIBUTES();
  771. LXW_PUSH_ATTRIBUTES_STR("count", "1");
  772. lxw_xml_start_tag(self->file, "cellStyles", &attributes);
  773. _write_cell_style(self);
  774. lxw_xml_end_tag(self->file, "cellStyles");
  775. LXW_FREE_ATTRIBUTES();
  776. }
  777. /*
  778. * Write the <dxfs> element.
  779. */
  780. STATIC void
  781. _write_dxfs(lxw_styles *self)
  782. {
  783. struct xml_attribute_list attributes;
  784. struct xml_attribute *attribute;
  785. LXW_INIT_ATTRIBUTES();
  786. LXW_PUSH_ATTRIBUTES_STR("count", "0");
  787. lxw_xml_empty_tag(self->file, "dxfs", &attributes);
  788. LXW_FREE_ATTRIBUTES();
  789. }
  790. /*
  791. * Write the <tableStyles> element.
  792. */
  793. STATIC void
  794. _write_table_styles(lxw_styles *self)
  795. {
  796. struct xml_attribute_list attributes;
  797. struct xml_attribute *attribute;
  798. LXW_INIT_ATTRIBUTES();
  799. LXW_PUSH_ATTRIBUTES_STR("count", "0");
  800. LXW_PUSH_ATTRIBUTES_STR("defaultTableStyle", "TableStyleMedium9");
  801. LXW_PUSH_ATTRIBUTES_STR("defaultPivotStyle", "PivotStyleLight16");
  802. lxw_xml_empty_tag(self->file, "tableStyles", &attributes);
  803. LXW_FREE_ATTRIBUTES();
  804. }
  805. /*****************************************************************************
  806. *
  807. * XML file assembly functions.
  808. *
  809. ****************************************************************************/
  810. /*
  811. * Assemble and write the XML file.
  812. */
  813. void
  814. lxw_styles_assemble_xml_file(lxw_styles *self)
  815. {
  816. /* Write the XML declaration. */
  817. _styles_xml_declaration(self);
  818. /* Add the style sheet. */
  819. _write_style_sheet(self);
  820. /* Write the number formats. */
  821. _write_num_fmts(self);
  822. /* Write the fonts. */
  823. _write_fonts(self);
  824. /* Write the fills. */
  825. _write_fills(self);
  826. /* Write the borders element. */
  827. _write_borders(self);
  828. /* Write the cellStyleXfs element. */
  829. _write_cell_style_xfs(self);
  830. /* Write the cellXfs element. */
  831. _write_cell_xfs(self);
  832. /* Write the cellStyles element. */
  833. _write_cell_styles(self);
  834. /* Write the dxfs element. */
  835. _write_dxfs(self);
  836. /* Write the tableStyles element. */
  837. _write_table_styles(self);
  838. /* Write the colors element. */
  839. /* _write_colors(self); */
  840. /* Close the style sheet tag. */
  841. lxw_xml_end_tag(self->file, "styleSheet");
  842. }
  843. /*****************************************************************************
  844. *
  845. * Public functions.
  846. *
  847. ****************************************************************************/