Added support for adding a macro button to a worksheet.

Feature request #39
This commit is contained in:
John McNamara 2021-08-26 21:29:31 +01:00
parent b185df6765
commit 3fcccedd06
34 changed files with 748 additions and 85 deletions

1
.indent.pro vendored
View file

@ -47,6 +47,7 @@
-T lxw_author_id
-T lxw_autofilter
-T lxw_border
-T lxw_button_options
-T lxw_cell
-T lxw_chart
-T lxw_chart_axis

View file

@ -1538,7 +1538,6 @@ typedef struct lxw_table_options {
*/
uint8_t last_column;
/**
* The `style_type` parameter can be used to set the style of the table,
* in conjunction with the `style_type_number` parameter:
@ -1892,6 +1891,50 @@ typedef struct lxw_comment_options {
} lxw_comment_options;
/**
* @brief Options for inserted buttons.
*
* Options for modifying buttons inserted via `worksheet_insert_button()`.
*
*/
typedef struct lxw_button_options {
/** Sets the caption on the button. The default is "Button n" where n is
* the current number of buttons in the worksheet, including this
* button. */
char *caption;
/** Name of the macro to run when the button is pressed. The macro must be
* included with workbook_add_vba_project(). */
char *macro;
/** Optional description or "Alt text" for the button. This field can be
* used to provide a text description of the button to help
* accessibility. Set to NULL to ignore the description field. */
char *description;
/** This option is used to set the width of the cell button box
* explicitly in pixels. The default width is 64 pixels. */
uint16_t width;
/** This option is used to set the height of the cell button box
* explicitly in pixels. The default height is 20 pixels. */
uint16_t height;
/** X scale of the button as a decimal. */
double x_scale;
/** Y scale of the button as a decimal. */
double y_scale;
/** Offset from the left of the cell in pixels. */
int32_t x_offset;
/** Offset from the top of the cell in pixels. */
int32_t y_offset;
} lxw_button_options;
/* Internal structure for VML object options. */
typedef struct lxw_vml_obj {
@ -1920,6 +1963,7 @@ typedef struct lxw_vml_obj {
char *text;
char *image_position;
char *name;
char *macro;
STAILQ_ENTRY (lxw_vml_obj) list_pointers;
} lxw_vml_obj;
@ -2078,6 +2122,7 @@ typedef struct lxw_worksheet {
struct lxw_vml_drawing_rel_ids *vml_drawing_rel_ids;
struct lxw_comment_objs *comment_objs;
struct lxw_comment_objs *header_image_objs;
struct lxw_comment_objs *button_objs;
struct lxw_table_objs *table_objs;
uint16_t table_count;
@ -2146,6 +2191,7 @@ typedef struct lxw_worksheet {
uint8_t num_validations;
uint8_t has_dynamic_arrays;
char *vba_codename;
uint16_t num_buttons;
lxw_color_t tab_color;
@ -2200,6 +2246,7 @@ typedef struct lxw_worksheet {
uint8_t has_comments;
uint8_t has_header_vml;
uint8_t has_background_image;
uint8_t has_buttons;
lxw_rel_tuple *external_vml_comment_link;
lxw_rel_tuple *external_comment_link;
lxw_rel_tuple *external_vml_header_link;
@ -4259,6 +4306,11 @@ lxw_error worksheet_conditional_format_range(lxw_worksheet *worksheet,
lxw_col_t last_col,
lxw_conditional_format
*conditional_format);
lxw_error worksheet_insert_button(lxw_worksheet *worksheet, lxw_row_t row_num,
lxw_col_t col_num,
lxw_button_options *options);
/**
* @brief Add an Excel table to a worksheet.
*

View file

@ -564,6 +564,7 @@ _write_vml_files(lxw_packager *self)
}
vml->comment_objs = worksheet->comment_objs;
vml->button_objs = worksheet->button_objs;
vml->vml_shape_id = worksheet->vml_shape_id;
vml->comment_display_default = worksheet->comment_display_default;

148
src/vml.c
View file

@ -127,10 +127,9 @@ _vml_write_text_valign(lxw_vml *self)
* Write the <x:FmlaMacro> element.
*/
STATIC void
_vml_write_fmla_macro(lxw_vml *self)
_vml_write_fmla_macro(lxw_vml *self, lxw_vml_obj *vml_obj)
{
lxw_xml_data_element(self->file, "x:FmlaMacro", "[0]!Button1_Click",
NULL);
lxw_xml_data_element(self->file, "x:FmlaMacro", vml_obj->macro, NULL);
}
/*
@ -182,11 +181,11 @@ _vml_write_rotation_lock(lxw_vml *self)
* Write the <x:Column> element.
*/
STATIC void
_vml_write_column(lxw_vml *self, lxw_vml_obj *comment_obj)
_vml_write_column(lxw_vml *self, lxw_vml_obj *vml_obj)
{
char data[LXW_ATTR_32];
lxw_snprintf(data, LXW_ATTR_32, "%d", comment_obj->col);
lxw_snprintf(data, LXW_ATTR_32, "%d", vml_obj->col);
lxw_xml_data_element(self->file, "x:Column", data, NULL);
}
@ -195,11 +194,11 @@ _vml_write_column(lxw_vml *self, lxw_vml_obj *comment_obj)
* Write the <x:Row> element.
*/
STATIC void
_vml_write_row(lxw_vml *self, lxw_vml_obj *comment_obj)
_vml_write_row(lxw_vml *self, lxw_vml_obj *vml_obj)
{
char data[LXW_ATTR_32];
lxw_snprintf(data, LXW_ATTR_32, "%d", comment_obj->row);
lxw_snprintf(data, LXW_ATTR_32, "%d", vml_obj->row);
lxw_xml_data_element(self->file, "x:Row", data, NULL);
}
@ -217,20 +216,20 @@ _vml_write_auto_fill(lxw_vml *self)
* Write the <x:Anchor> element.
*/
STATIC void
_vml_write_anchor(lxw_vml *self, lxw_vml_obj *comment_obj)
_vml_write_anchor(lxw_vml *self, lxw_vml_obj *vml_obj)
{
char anchor_data[LXW_MAX_ATTRIBUTE_LENGTH];
lxw_snprintf(anchor_data,
LXW_MAX_ATTRIBUTE_LENGTH,
"%d, %d, %d, %d, %d, %d, %d, %d",
comment_obj->from.col,
(uint32_t) comment_obj->from.col_offset,
comment_obj->from.row,
(uint32_t) comment_obj->from.row_offset,
comment_obj->to.col,
(uint32_t) comment_obj->to.col_offset,
comment_obj->to.row, (uint32_t) comment_obj->to.row_offset);
vml_obj->from.col,
(uint32_t) vml_obj->from.col_offset,
vml_obj->from.row,
(uint32_t) vml_obj->from.row_offset,
vml_obj->to.col,
(uint32_t) vml_obj->to.col_offset,
vml_obj->to.row, (uint32_t) vml_obj->to.row_offset);
lxw_xml_data_element(self->file, "x:Anchor", anchor_data, NULL);
}
@ -311,7 +310,7 @@ _vml_write_shapetype_lock(lxw_vml *self)
* Write the <font> element.
*/
STATIC void
_vml_write_font(lxw_vml *self)
_vml_write_font(lxw_vml *self, lxw_vml_obj *vml_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
@ -321,7 +320,7 @@ _vml_write_font(lxw_vml *self)
LXW_PUSH_ATTRIBUTES_STR("size", "220");
LXW_PUSH_ATTRIBUTES_STR("color", "#000000");
lxw_xml_data_element(self->file, "font", "Button 1", &attributes);
lxw_xml_data_element(self->file, "font", vml_obj->name, &attributes);
LXW_FREE_ATTRIBUTES();
}
@ -471,7 +470,7 @@ _vml_write_image_shapetype(lxw_vml *self)
* Write the <x:ClientData> element.
*/
STATIC void
_vml_write_button_client_data(lxw_vml *self)
_vml_write_button_client_data(lxw_vml *self, lxw_vml_obj *vml_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
@ -482,7 +481,7 @@ _vml_write_button_client_data(lxw_vml *self)
lxw_xml_start_tag(self->file, "x:ClientData", &attributes);
/* Write the <x:Anchor> element. */
_vml_write_anchor(self, NULL);
_vml_write_anchor(self, vml_obj);
/* Write the x:PrintObject element. */
_vml_write_print_object(self);
@ -491,7 +490,7 @@ _vml_write_button_client_data(lxw_vml *self)
_vml_write_auto_fill(self);
/* Write the x:FmlaMacro element. */
_vml_write_fmla_macro(self);
_vml_write_fmla_macro(self, vml_obj);
/* Write the x:TextHAlign element. */
_vml_write_text_halign(self);
@ -508,7 +507,7 @@ _vml_write_button_client_data(lxw_vml *self)
* Write the <div> element.
*/
STATIC void
_vml_write_button_div(lxw_vml *self)
_vml_write_button_div(lxw_vml *self, lxw_vml_obj *vml_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
@ -519,7 +518,7 @@ _vml_write_button_div(lxw_vml *self)
lxw_xml_start_tag(self->file, "div", &attributes);
/* Write the font element. */
_vml_write_font(self);
_vml_write_font(self, vml_obj);
lxw_xml_end_tag(self->file, "div");
@ -530,7 +529,7 @@ _vml_write_button_div(lxw_vml *self)
* Write the <v:textbox> element.
*/
STATIC void
_vml_write_button_textbox(lxw_vml *self)
_vml_write_button_textbox(lxw_vml *self, lxw_vml_obj *vml_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
@ -542,7 +541,7 @@ _vml_write_button_textbox(lxw_vml *self)
lxw_xml_start_tag(self->file, "v:textbox", &attributes);
/* Write the div element. */
_vml_write_button_div(self);
_vml_write_button_div(self, vml_obj);
lxw_xml_end_tag(self->file, "v:textbox");
@ -592,22 +591,49 @@ _vml_write_button_path(lxw_vml *self)
* Write the <v:shape> element for buttons.
*/
STATIC void
_vml_write_button_shape(lxw_vml *self)
_vml_write_button_shape(lxw_vml *self, uint32_t vml_shape_id,
uint32_t z_index, lxw_vml_obj *vml_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
char id[] = "_x0000_s1025";
char type[] = "#_x0000_t201";
char style[] = "position:absolute;margin-left:96pt;margin-top:15pt;"
"width:48pt;height:15pt;z-index:1;mso-wrap-style:tight";
char o_button[] = "t";
char fillcolor[] = "buttonFace [67]";
char strokecolor[] = "windowText [64]";
char o_insetmode[] = "auto";
char id[LXW_ATTR_32];
char margin_left[LXW_ATTR_32];
char margin_top[LXW_ATTR_32];
char width[LXW_ATTR_32];
char height[LXW_ATTR_32];
char style[LXW_MAX_ATTRIBUTE_LENGTH];
lxw_sprintf_dbl(margin_left, vml_obj->col_absolute * 0.75);
lxw_sprintf_dbl(margin_top, vml_obj->row_absolute * 0.75);
lxw_sprintf_dbl(width, vml_obj->width * 0.75);
lxw_sprintf_dbl(height, vml_obj->height * 0.75);
lxw_snprintf(id, LXW_ATTR_32, "_x0000_s%d", vml_shape_id);
lxw_snprintf(style,
LXW_MAX_ATTRIBUTE_LENGTH,
"position:absolute;"
"margin-left:%spt;"
"margin-top:%spt;"
"width:%spt;"
"height:%spt;"
"z-index:%d;"
"mso-wrap-style:tight",
margin_left, margin_top, width, height, z_index);
LXW_INIT_ATTRIBUTES();
LXW_PUSH_ATTRIBUTES_STR("id", id);
LXW_PUSH_ATTRIBUTES_STR("type", type);
if (vml_obj->text)
LXW_PUSH_ATTRIBUTES_STR("alt", vml_obj->text);
LXW_PUSH_ATTRIBUTES_STR("style", style);
LXW_PUSH_ATTRIBUTES_STR("o:button", o_button);
LXW_PUSH_ATTRIBUTES_STR("fillcolor", fillcolor);
@ -623,10 +649,10 @@ _vml_write_button_shape(lxw_vml *self)
_vml_write_rotation_lock(self);
/* Write the v:textbox element. */
_vml_write_button_textbox(self);
_vml_write_button_textbox(self, vml_obj);
/* Write the x:ClientData element. */
_vml_write_button_client_data(self);
_vml_write_button_client_data(self, vml_obj);
lxw_xml_end_tag(self->file, "v:shape");
@ -672,7 +698,7 @@ _vml_write_button_shapetype(lxw_vml *self)
* Write the <x:ClientData> element.
*/
STATIC void
_vml_write_comment_client_data(lxw_vml *self, lxw_vml_obj *comment_obj)
_vml_write_comment_client_data(lxw_vml *self, lxw_vml_obj *vml_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
@ -689,19 +715,19 @@ _vml_write_comment_client_data(lxw_vml *self, lxw_vml_obj *comment_obj)
_vml_write_size_with_cells(self);
/* Write the <x:Anchor> element. */
_vml_write_anchor(self, comment_obj);
_vml_write_anchor(self, vml_obj);
/* Write the <x:AutoFill> element. */
_vml_write_auto_fill(self);
/* Write the <x:Row> element. */
_vml_write_row(self, comment_obj);
_vml_write_row(self, vml_obj);
/* Write the <x:Column> element. */
_vml_write_column(self, comment_obj);
_vml_write_column(self, vml_obj);
/* Write the x:Visible element. */
if (comment_obj->visible == LXW_COMMENT_DISPLAY_VISIBLE)
if (vml_obj->visible == LXW_COMMENT_DISPLAY_VISIBLE)
_vml_write_visible(self);
lxw_xml_end_tag(self->file, "x:ClientData");
@ -793,7 +819,7 @@ _vml_write_comment_path(lxw_vml *self, uint8_t has_gradient, char *type)
*/
STATIC void
_vml_write_comment_shape(lxw_vml *self, uint32_t vml_shape_id,
uint32_t z_index, lxw_vml_obj *comment_obj)
uint32_t z_index, lxw_vml_obj *vml_obj)
{
struct xml_attribute_list attributes;
struct xml_attribute *attribute;
@ -808,24 +834,24 @@ _vml_write_comment_shape(lxw_vml *self, uint32_t vml_shape_id,
char type[] = "#_x0000_t202";
char o_insetmode[] = "auto";
lxw_sprintf_dbl(margin_left, comment_obj->col_absolute * 0.75);
lxw_sprintf_dbl(margin_top, comment_obj->row_absolute * 0.75);
lxw_sprintf_dbl(width, comment_obj->width * 0.75);
lxw_sprintf_dbl(height, comment_obj->height * 0.75);
lxw_sprintf_dbl(margin_left, vml_obj->col_absolute * 0.75);
lxw_sprintf_dbl(margin_top, vml_obj->row_absolute * 0.75);
lxw_sprintf_dbl(width, vml_obj->width * 0.75);
lxw_sprintf_dbl(height, vml_obj->height * 0.75);
lxw_snprintf(id, LXW_ATTR_32, "_x0000_s%d", vml_shape_id);
if (comment_obj->visible == LXW_COMMENT_DISPLAY_DEFAULT)
comment_obj->visible = self->comment_display_default;
if (vml_obj->visible == LXW_COMMENT_DISPLAY_DEFAULT)
vml_obj->visible = self->comment_display_default;
if (comment_obj->visible == LXW_COMMENT_DISPLAY_VISIBLE)
if (vml_obj->visible == LXW_COMMENT_DISPLAY_VISIBLE)
lxw_snprintf(visible, LXW_ATTR_32, "visible");
else
lxw_snprintf(visible, LXW_ATTR_32, "hidden");
if (comment_obj->color)
if (vml_obj->color)
lxw_snprintf(fillcolor, LXW_ATTR_32, "#%06x",
comment_obj->color & LXW_COLOR_MASK);
vml_obj->color & LXW_COLOR_MASK);
else
lxw_snprintf(fillcolor, LXW_ATTR_32, "#%06x", 0xffffe1);
@ -862,7 +888,7 @@ _vml_write_comment_shape(lxw_vml *self, uint32_t vml_shape_id,
_vml_write_comment_textbox(self);
/* Write the x:ClientData element. */
_vml_write_comment_client_data(self, comment_obj);
_vml_write_comment_client_data(self, vml_obj);
lxw_xml_end_tag(self->file, "v:shape");
@ -981,7 +1007,22 @@ lxw_vml_assemble_xml_file(lxw_vml *self)
/* Write the o:shapelayout element. */
_vml_write_shapelayout(self);
if (self->comment_objs) {
if (self->button_objs && !STAILQ_EMPTY(self->button_objs)) {
/* Write the <v:shapetype> element. */
_vml_write_button_shapetype(self);
STAILQ_FOREACH(button_obj, self->button_objs, list_pointers) {
self->vml_shape_id++;
/* Write the <v:shape> element. */
_vml_write_button_shape(self, self->vml_shape_id, z_index,
button_obj);
z_index++;
}
}
if (self->comment_objs && !STAILQ_EMPTY(self->comment_objs)) {
/* Write the <v:shapetype> element. */
_vml_write_comment_shapetype(self);
@ -996,18 +1037,7 @@ lxw_vml_assemble_xml_file(lxw_vml *self)
}
}
if (self->button_objs) {
/* Write the <v:shapetype> element. */
_vml_write_button_shapetype(self);
STAILQ_FOREACH(button_obj, self->button_objs, list_pointers) {
/* Write the <v:shape> element. */
_vml_write_button_shape(self);
}
}
if (self->image_objs) {
if (self->image_objs && !STAILQ_EMPTY(self->image_objs)) {
/* Write the <v:shapetype> element. */
_vml_write_image_shapetype(self);

View file

@ -153,6 +153,10 @@ lxw_worksheet_new(lxw_worksheet_init_data *init_data)
GOTO_LABEL_ON_MEM_ERROR(worksheet->header_image_objs, mem_error);
STAILQ_INIT(worksheet->header_image_objs);
worksheet->button_objs = calloc(1, sizeof(struct lxw_comment_objs));
GOTO_LABEL_ON_MEM_ERROR(worksheet->button_objs, mem_error);
STAILQ_INIT(worksheet->button_objs);
worksheet->selections = calloc(1, sizeof(struct lxw_selections));
GOTO_LABEL_ON_MEM_ERROR(worksheet->selections, mem_error);
STAILQ_INIT(worksheet->selections);
@ -303,6 +307,7 @@ _free_vml_object(lxw_vml_obj *vml_obj)
free(vml_obj->text);
free(vml_obj->image_position);
free(vml_obj->name);
free(vml_obj->macro);
free(vml_obj);
}
@ -515,7 +520,7 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
lxw_col_t col;
lxw_merged_range *merged_range;
lxw_object_properties *object_props;
lxw_vml_obj *header_image_vml;
lxw_vml_obj *vml_obj;
lxw_selection *selection;
lxw_data_val_obj *data_validation;
lxw_rel_tuple *relationship;
@ -611,14 +616,24 @@ lxw_worksheet_free(lxw_worksheet *worksheet)
if (worksheet->header_image_objs) {
while (!STAILQ_EMPTY(worksheet->header_image_objs)) {
header_image_vml = STAILQ_FIRST(worksheet->header_image_objs);
vml_obj = STAILQ_FIRST(worksheet->header_image_objs);
STAILQ_REMOVE_HEAD(worksheet->header_image_objs, list_pointers);
_free_vml_object(header_image_vml);
_free_vml_object(vml_obj);
}
free(worksheet->header_image_objs);
}
if (worksheet->button_objs) {
while (!STAILQ_EMPTY(worksheet->button_objs)) {
vml_obj = STAILQ_FIRST(worksheet->button_objs);
STAILQ_REMOVE_HEAD(worksheet->button_objs, list_pointers);
_free_vml_object(vml_obj);
}
free(worksheet->button_objs);
}
if (worksheet->selections) {
while (!STAILQ_EMPTY(worksheet->selections)) {
selection = STAILQ_FIRST(worksheet->selections);
@ -3107,35 +3122,131 @@ _get_comment_params(lxw_vml_obj *comment, lxw_comment_options *options)
}
/*
* Calculate the comment object position and vertices.
* This function handles the additional optional parameters to
* worksheet_insert_button() as well as calculating the button object
* position and vertices.
*/
lxw_error
_get_button_params(lxw_vml_obj *button, uint16_t button_number,
lxw_button_options *options)
{
int32_t x_offset = 0;
int32_t y_offset = 0;
uint32_t height = LXW_DEF_ROW_HEIGHT_PIXELS;
uint32_t width = LXW_DEF_COL_WIDTH_PIXELS;
double x_scale = 1.0;
double y_scale = 1.0;
lxw_row_t row = button->row;
lxw_col_t col = button->col;
char buffer[LXW_ATTR_32];
uint8_t has_caption = LXW_FALSE;
uint8_t has_macro = LXW_FALSE;
size_t len;
/* Set any user defined options. */
if (options) {
if (options->width > 0.0)
width = options->width;
if (options->height > 0.0)
height = options->height;
if (options->x_scale > 0.0)
x_scale = options->x_scale;
if (options->y_scale > 0.0)
y_scale = options->y_scale;
if (options->x_offset != 0)
x_offset = options->x_offset;
if (options->y_offset != 0)
y_offset = options->y_offset;
if (options->caption) {
button->name = lxw_strdup(options->caption);
RETURN_ON_MEM_ERROR(button->name, LXW_ERROR_MEMORY_MALLOC_FAILED);
has_caption = LXW_TRUE;
}
if (options->macro) {
len = sizeof("[0]!") + strlen(options->macro);
button->macro = calloc(1, len);
RETURN_ON_MEM_ERROR(button->macro,
LXW_ERROR_MEMORY_MALLOC_FAILED);
if (button->macro)
lxw_snprintf(button->macro, len, "[0]!%s", options->macro);
has_macro = LXW_TRUE;
}
if (options->description) {
button->text = lxw_strdup(options->description);
RETURN_ON_MEM_ERROR(button->text, LXW_ERROR_MEMORY_MALLOC_FAILED);
}
}
if (!has_caption) {
lxw_snprintf(buffer, LXW_ATTR_32, "Button %d", button_number);
button->name = lxw_strdup(buffer);
RETURN_ON_MEM_ERROR(button->name, LXW_ERROR_MEMORY_MALLOC_FAILED);
}
if (!has_macro) {
lxw_snprintf(buffer, LXW_ATTR_32, "[0]!Button%d_Click",
button_number);
button->macro = lxw_strdup(buffer);
RETURN_ON_MEM_ERROR(button->macro, LXW_ERROR_MEMORY_MALLOC_FAILED);
}
/* Scale the width/height to the default/user scale and round to the
* nearest pixel. */
width = (uint32_t) (0.5 + x_scale * width);
height = (uint32_t) (0.5 + y_scale * height);
button->width = width;
button->height = height;
button->start_col = col;
button->start_row = row;
button->x_offset = x_offset;
button->y_offset = y_offset;
return LXW_NO_ERROR;
}
/*
* Calculate the vml_obj object position and vertices.
*/
void
_worksheet_position_vml_object(lxw_worksheet *self, lxw_vml_obj *comment)
_worksheet_position_vml_object(lxw_worksheet *self, lxw_vml_obj *vml_obj)
{
lxw_object_properties object_props;
lxw_drawing_object drawing_object;
object_props.col = comment->start_col;
object_props.row = comment->start_row;
object_props.x_offset = comment->x_offset;
object_props.y_offset = comment->y_offset;
object_props.width = comment->width;
object_props.height = comment->height;
object_props.col = vml_obj->start_col;
object_props.row = vml_obj->start_row;
object_props.x_offset = vml_obj->x_offset;
object_props.y_offset = vml_obj->y_offset;
object_props.width = vml_obj->width;
object_props.height = vml_obj->height;
drawing_object.anchor = LXW_OBJECT_DONT_MOVE_DONT_SIZE;
_worksheet_position_object_pixels(self, &object_props, &drawing_object);
comment->from.col = drawing_object.from.col;
comment->from.row = drawing_object.from.row;
comment->from.col_offset = drawing_object.from.col_offset;
comment->from.row_offset = drawing_object.from.row_offset;
comment->to.col = drawing_object.to.col;
comment->to.row = drawing_object.to.row;
comment->to.col_offset = drawing_object.to.col_offset;
comment->to.row_offset = drawing_object.to.row_offset;
comment->col_absolute = drawing_object.col_absolute;
comment->row_absolute = drawing_object.row_absolute;
vml_obj->from.col = drawing_object.from.col;
vml_obj->from.row = drawing_object.from.row;
vml_obj->from.col_offset = drawing_object.from.col_offset;
vml_obj->from.row_offset = drawing_object.from.row_offset;
vml_obj->to.col = drawing_object.to.col;
vml_obj->to.row = drawing_object.to.row;
vml_obj->to.col_offset = drawing_object.to.col_offset;
vml_obj->to.row_offset = drawing_object.to.row_offset;
vml_obj->col_absolute = drawing_object.col_absolute;
vml_obj->row_absolute = drawing_object.row_absolute;
}
/*
@ -9129,10 +9240,10 @@ worksheet_add_table(lxw_worksheet *self, lxw_row_t first_row,
lxw_table_column **columns;
if (self->optimize) {
LXW_WARN_FORMAT("worksheet_add_table(): "
"worksheet tables aren't supported in "
"'constant_memory' mode");
return LXW_ERROR_FEATURE_NOT_SUPPORTED;
LXW_WARN_FORMAT("worksheet_add_table(): "
"worksheet tables aren't supported in "
"'constant_memory' mode");
return LXW_ERROR_FEATURE_NOT_SUPPORTED;
}
/* Swap last row/col with first row/col as necessary */
@ -10991,6 +11102,49 @@ worksheet_conditional_format_cell(lxw_worksheet *self,
row, col, options);
}
/*
* Insert a button object into the worksheet.
*/
lxw_error
worksheet_insert_button(lxw_worksheet *self, lxw_row_t row_num,
lxw_col_t col_num, lxw_button_options *options)
{
lxw_error err;
lxw_vml_obj *button;
err = _check_dimensions(self, row_num, col_num, LXW_TRUE, LXW_TRUE);
if (err)
return err;
button = calloc(1, sizeof(lxw_vml_obj));
GOTO_LABEL_ON_MEM_ERROR(button, mem_error);
button->row = row_num;
button->col = col_num;
/* Set user and default parameters for the button. */
err = _get_button_params(button, 1 + self->num_buttons, options);
if (err)
goto mem_error;
/* Calculate the worksheet position of the button. */
_worksheet_position_vml_object(self, button);
self->has_vml = LXW_TRUE;
self->has_buttons = LXW_TRUE;
self->num_buttons++;
STAILQ_INSERT_TAIL(self->button_objs, button, list_pointers);
return LXW_NO_ERROR;
mem_error:
if (button)
_free_vml_object(button);
return LXW_ERROR_MEMORY_MALLOC_FAILED;
}
/*
* Set the VBA name for the worksheet.
*/

Binary file not shown.

View file

@ -0,0 +1,20 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button01.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
worksheet_insert_button(worksheet, CELL("C2"), NULL);
return workbook_close(workbook);
}

View file

@ -0,0 +1,22 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button02.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
lxw_button_options options = {.x_offset = 4, .y_offset = 3, .caption = "my text"};
worksheet_insert_button(worksheet, CELL("B4"), &options);
return workbook_close(workbook);
}

View file

@ -0,0 +1,21 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button03.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
worksheet_insert_button(worksheet, CELL("C2"), NULL);
worksheet_insert_button(worksheet, CELL("E5"), NULL);
return workbook_close(workbook);
}

View file

@ -0,0 +1,22 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button04.xlsx");
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
worksheet_insert_button(worksheet1, CELL("C2"), NULL);
worksheet_insert_button(worksheet2, CELL("E5"), NULL);
return workbook_close(workbook);
}

View file

@ -0,0 +1,22 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button05.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
lxw_button_options options = {.x_scale = 2, .y_scale = 1.5, .macro = "my_macro"};
worksheet_insert_button(worksheet, CELL("C2"), &options);
return workbook_close(workbook);
}

View file

@ -0,0 +1,22 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button06.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
lxw_button_options options = {.width = 128, .height = 30, .macro = "my_macro"};
worksheet_insert_button(worksheet, CELL("C2"), &options);
return workbook_close(workbook);
}

View file

@ -0,0 +1,24 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button07.xlsm");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
lxw_button_options options = {.caption = "Hello", .macro = "say_hello"};
worksheet_insert_button(worksheet, CELL("C2"), &options);
workbook_add_vba_project(workbook, "images/vbaProject02.bin");
return workbook_close(workbook);
}

View file

@ -0,0 +1,25 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button08.xlsx");
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
worksheet_insert_button(worksheet1, CELL("C2"), NULL);
worksheet_write_comment(worksheet2, CELL("A1"), "Foo");
worksheet_set_comments_author(worksheet2, "John");
return workbook_close(workbook);
}

View file

@ -0,0 +1,25 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button09.xlsx");
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
worksheet_insert_button(worksheet2, CELL("C2"), NULL);
worksheet_write_comment(worksheet1, CELL("A1"), "Foo");
worksheet_set_comments_author(worksheet1, "John");
return workbook_close(workbook);
}

View file

@ -0,0 +1,29 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button10.xlsx");
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, NULL);
worksheet_write_comment(worksheet1, CELL("A1"), "Some text");
worksheet_insert_button(worksheet2, CELL("B2"), NULL);
worksheet_write_comment(worksheet3, CELL("C2"), "More text");
worksheet_set_comments_author(worksheet1, "John");
worksheet_set_comments_author(worksheet3, "John");
return workbook_close(workbook);
}

View file

@ -0,0 +1,29 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button11.xlsx");
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
lxw_worksheet *worksheet2 = workbook_add_worksheet(workbook, NULL);
lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, NULL);
worksheet_insert_button(worksheet1, CELL("C2"), NULL);
worksheet_write_comment(worksheet2, CELL("B2"), "Some text");
worksheet_write_comment(worksheet3, CELL("C3"), "More text");
worksheet_set_comments_author(worksheet2, "John");
worksheet_set_comments_author(worksheet3, "John");
return workbook_close(workbook);
}

View file

@ -0,0 +1,28 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button12.xlsx");
lxw_worksheet *worksheet1 = workbook_add_worksheet(workbook, NULL);
workbook_add_worksheet(workbook, NULL);
lxw_worksheet *worksheet3 = workbook_add_worksheet(workbook, NULL);
worksheet_write_comment(worksheet1, CELL("A1"), "Some text");
worksheet_insert_button(worksheet1, CELL("C2"), NULL);
worksheet_write_comment(worksheet3, CELL("C3"), "More text");
worksheet_set_comments_author(worksheet1, "John");
worksheet_set_comments_author(worksheet3, "John");
return workbook_close(workbook);
}

View file

@ -0,0 +1,27 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button13.xlsm");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
lxw_button_options options = {.caption = "Hello", .macro = "say_hello"};
workbook_set_vba_name(workbook, "ThisWorkbook");
worksheet_set_vba_name(worksheet, "Sheet1");
worksheet_insert_button(worksheet, CELL("C2"), &options);
workbook_add_vba_project(workbook, "images/vbaProject02.bin");
return workbook_close(workbook);
}

View file

@ -0,0 +1,28 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button14.xlsm");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
lxw_button_options options = {.caption = "Hello", .macro = "say_hello"};
/* Implicit vba names.
workbook_set_vba_name(workbook, "ThisWorkbook");
worksheet_set_vba_name(worksheet, "Sheet1");
*/
worksheet_insert_button(worksheet, CELL("C2"), &options);
workbook_add_vba_project(workbook, "images/vbaProject02.bin");
return workbook_close(workbook);
}

View file

@ -0,0 +1,22 @@
/*****************************************************************************
* Test cases for libxlsxwriter.
*
* Test to compare output against Excel files.
*
* Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
*
*/
#include "xlsxwriter.h"
int main() {
lxw_workbook *workbook = workbook_new("test_button15.xlsx");
lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL);
lxw_button_options options = {.description = "Some alternative text"};
worksheet_insert_button(worksheet, CELL("C2"), &options);
return workbook_close(workbook);
}

View file

@ -0,0 +1,59 @@
###############################################################################
#
# Tests for libxlsxwriter.
#
# Copyright 2014-2021, John McNamara, jmcnamara@cpan.org
#
import base_test_class
class TestCompareXLSXFiles(base_test_class.XLSXBaseTest):
"""
Test file created with libxlsxwriter against a file created by Excel.
"""
def test_button01(self):
self.run_exe_test('test_button01')
def test_button02(self):
self.run_exe_test('test_button02')
def test_button03(self):
self.run_exe_test('test_button03')
def test_button04(self):
self.run_exe_test('test_button04')
def test_button05(self):
self.run_exe_test('test_button05')
def test_button06(self):
self.run_exe_test('test_button06', 'button05.xlsx')
def test_button07(self):
self.run_exe_test('test_button07', 'button07.xlsm')
def test_button08(self):
self.run_exe_test('test_button08')
def test_button09(self):
self.run_exe_test('test_button09')
def test_button10(self):
self.run_exe_test('test_button10')
def test_button11(self):
self.run_exe_test('test_button11')
def test_button12(self):
self.run_exe_test('test_button12')
def test_button13(self):
self.run_exe_test('test_button13', 'button07.xlsm')
def test_button14(self):
self.run_exe_test('test_button14', 'button07.xlsm')
def test_button15(self):
self.run_exe_test('test_button15')

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.