write_xlsx 1.00.0 → 1.01.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Changes +15 -0
  4. data/examples/a_simple.rb +1 -1
  5. data/examples/add_vba_project.rb +1 -1
  6. data/examples/array_formula.rb +1 -1
  7. data/examples/chart_area.rb +5 -2
  8. data/examples/chart_bar.rb +5 -2
  9. data/examples/chart_clustered.rb +1 -1
  10. data/examples/chart_column.rb +5 -2
  11. data/examples/chart_combined.rb +1 -1
  12. data/examples/chart_data_table.rb +9 -3
  13. data/examples/chart_data_tools.rb +25 -7
  14. data/examples/chart_doughnut.rb +17 -5
  15. data/examples/chart_gauge.rb +73 -0
  16. data/examples/chart_line.rb +5 -2
  17. data/examples/chart_pareto.rb +1 -1
  18. data/examples/chart_pie.rb +9 -3
  19. data/examples/chart_radar.rb +13 -4
  20. data/examples/chart_scatter.rb +5 -2
  21. data/examples/chart_secondary_axis.rb +5 -2
  22. data/examples/chart_stock.rb +1 -1
  23. data/examples/chart_styles.rb +1 -1
  24. data/examples/colors.rb +1 -1
  25. data/examples/data_validate.rb +1 -1
  26. data/examples/date_time.rb +1 -1
  27. data/examples/demo.rb +4 -1
  28. data/examples/formats.rb +1 -1
  29. data/examples/headers.rb +1 -1
  30. data/examples/hide_row_col.rb +1 -1
  31. data/examples/hide_sheet.rb +1 -1
  32. data/examples/hyperlink1.rb +1 -1
  33. data/examples/indent.rb +1 -1
  34. data/examples/macros.rb +1 -1
  35. data/examples/merge1.rb +1 -1
  36. data/examples/merge2.rb +1 -1
  37. data/examples/merge3.rb +1 -1
  38. data/examples/merge4.rb +1 -1
  39. data/examples/merge5.rb +1 -1
  40. data/examples/merge6.rb +1 -1
  41. data/examples/outline.rb +1 -1
  42. data/examples/outline_collapsed.rb +1 -1
  43. data/examples/panes.rb +1 -1
  44. data/examples/properties.rb +1 -1
  45. data/examples/regions.rb +1 -1
  46. data/examples/rich_strings.rb +1 -1
  47. data/examples/right_to_left.rb +1 -1
  48. data/examples/shape1.rb +1 -1
  49. data/examples/shape2.rb +1 -1
  50. data/examples/shape3.rb +1 -1
  51. data/examples/shape4.rb +1 -1
  52. data/examples/shape5.rb +1 -1
  53. data/examples/shape6.rb +1 -1
  54. data/examples/shape7.rb +1 -1
  55. data/examples/shape8.rb +1 -1
  56. data/examples/shape_all.rb +1 -1
  57. data/examples/sparklines1.rb +1 -1
  58. data/examples/sparklines2.rb +1 -1
  59. data/examples/stats.rb +1 -1
  60. data/examples/stats_ext.rb +1 -1
  61. data/examples/stocks.rb +1 -1
  62. data/examples/tab_colors.rb +1 -1
  63. data/examples/tables.rb +1 -1
  64. data/lib/write_xlsx/chart.rb +18 -13
  65. data/lib/write_xlsx/chart/area.rb +1 -1
  66. data/lib/write_xlsx/chart/bar.rb +1 -1
  67. data/lib/write_xlsx/chart/column.rb +1 -1
  68. data/lib/write_xlsx/chart/doughnut.rb +1 -1
  69. data/lib/write_xlsx/chart/line.rb +1 -1
  70. data/lib/write_xlsx/chart/pie.rb +21 -8
  71. data/lib/write_xlsx/chart/radar.rb +1 -1
  72. data/lib/write_xlsx/chart/scatter.rb +1 -1
  73. data/lib/write_xlsx/chart/stock.rb +1 -1
  74. data/lib/write_xlsx/chartsheet.rb +5 -5
  75. data/lib/write_xlsx/drawing.rb +28 -8
  76. data/lib/write_xlsx/package/comments.rb +7 -7
  77. data/lib/write_xlsx/shape.rb +4 -3
  78. data/lib/write_xlsx/sheets.rb +11 -1
  79. data/lib/write_xlsx/sparkline.rb +1 -1
  80. data/lib/write_xlsx/utility.rb +18 -6
  81. data/lib/write_xlsx/version.rb +1 -1
  82. data/lib/write_xlsx/workbook.rb +5 -5
  83. data/lib/write_xlsx/worksheet.rb +113 -125
  84. data/test/drawing/test_drawing_chart_01.rb +6 -2
  85. data/test/drawing/test_drawing_image_01.rb +12 -3
  86. data/test/drawing/test_drawing_shape_01.rb +8 -5
  87. data/test/drawing/test_drawing_shape_02.rb +12 -5
  88. data/test/drawing/test_drawing_shape_03.rb +8 -5
  89. data/test/drawing/test_drawing_shape_04.rb +8 -24
  90. data/test/drawing/test_drawing_shape_05.rb +8 -5
  91. data/test/drawing/test_drawing_shape_06.rb +11 -6
  92. data/test/drawing/test_drawing_shape_07.rb +11 -6
  93. data/test/drawing/test_write_a_graphic_frame_locks.rb +1 -1
  94. data/test/drawing/test_write_c_chart.rb +1 -1
  95. data/test/drawing/test_write_c_nv_graphic_frame_pr.rb +1 -1
  96. data/test/drawing/test_write_c_nv_pr.rb +1 -1
  97. data/test/drawing/test_write_col.rb +1 -1
  98. data/test/drawing/test_write_col_off.rb +1 -1
  99. data/test/drawing/test_write_ext.rb +1 -1
  100. data/test/drawing/test_write_pos.rb +1 -1
  101. data/test/drawing/test_write_row.rb +1 -1
  102. data/test/drawing/test_write_row_off.rb +1 -1
  103. data/test/drawing/test_write_xfrm_extension.rb +1 -1
  104. data/test/drawing/test_write_xfrm_offset.rb +1 -1
  105. data/test/perl_output/chart_gauge.xlsx +0 -0
  106. data/test/regression/test_chart_axis26.rb +10 -8
  107. data/test/regression/test_chart_axis27.rb +1 -1
  108. data/test/regression/test_chart_axis28.rb +1 -1
  109. data/test/regression/test_chart_axis29.rb +1 -1
  110. data/test/regression/test_chart_axis33.rb +1 -1
  111. data/test/regression/test_chart_axis44.rb +54 -0
  112. data/test/regression/test_chart_axis45.rb +54 -0
  113. data/test/regression/test_chart_axis46.rb +54 -0
  114. data/test/regression/test_chart_combined10.rb +43 -0
  115. data/test/regression/test_chart_combined11.rb +63 -0
  116. data/test/regression/test_chart_data_labels25.rb +1 -1
  117. data/test/regression/test_chart_doughnut07.rb +37 -0
  118. data/test/regression/test_chart_font09.rb +1 -1
  119. data/test/regression/test_chart_size03.rb +4 -1
  120. data/test/regression/test_comment14.rb +29 -0
  121. data/test/regression/test_image08.rb +5 -4
  122. data/test/regression/test_image15.rb +4 -2
  123. data/test/regression/test_image28.rb +1 -1
  124. data/test/regression/test_object_position01.rb +26 -0
  125. data/test/regression/test_object_position02.rb +26 -0
  126. data/test/regression/test_object_position03.rb +26 -0
  127. data/test/regression/test_object_position04.rb +44 -0
  128. data/test/regression/test_object_position06.rb +28 -0
  129. data/test/regression/test_object_position07.rb +28 -0
  130. data/test/regression/test_object_position08.rb +47 -0
  131. data/test/regression/test_object_position09.rb +50 -0
  132. data/test/regression/test_object_position10.rb +28 -0
  133. data/test/regression/test_shape_connect01.rb +4 -2
  134. data/test/regression/xlsx_files/chart_axis26.xlsx +0 -0
  135. data/test/regression/xlsx_files/chart_axis27.xlsx +0 -0
  136. data/test/regression/xlsx_files/chart_axis28.xlsx +0 -0
  137. data/test/regression/xlsx_files/chart_axis29.xlsx +0 -0
  138. data/test/regression/xlsx_files/chart_axis33.xlsx +0 -0
  139. data/test/regression/xlsx_files/chart_axis44.xlsx +0 -0
  140. data/test/regression/xlsx_files/chart_axis45.xlsx +0 -0
  141. data/test/regression/xlsx_files/chart_axis46.xlsx +0 -0
  142. data/test/regression/xlsx_files/chart_combined10.xlsx +0 -0
  143. data/test/regression/xlsx_files/chart_combined11.xlsx +0 -0
  144. data/test/regression/xlsx_files/chart_data_labels25.xlsx +0 -0
  145. data/test/regression/xlsx_files/chart_doughnut07.xlsx +0 -0
  146. data/test/regression/xlsx_files/chart_font09.xlsx +0 -0
  147. data/test/regression/xlsx_files/comment14.xlsx +0 -0
  148. data/test/regression/xlsx_files/object_position01.xlsx +0 -0
  149. data/test/regression/xlsx_files/object_position02.xlsx +0 -0
  150. data/test/regression/xlsx_files/object_position03.xlsx +0 -0
  151. data/test/regression/xlsx_files/object_position04.xlsx +0 -0
  152. data/test/regression/xlsx_files/object_position06.xlsx +0 -0
  153. data/test/regression/xlsx_files/object_position07.xlsx +0 -0
  154. data/test/regression/xlsx_files/object_position08.xlsx +0 -0
  155. data/test/regression/xlsx_files/object_position09.xlsx +0 -0
  156. data/test/regression/xlsx_files/object_position10.xlsx +0 -0
  157. data/test/test_example_match.rb +836 -771
  158. data/test/workbook/test_check_sheetname.rb +61 -0
  159. metadata +75 -6
@@ -230,10 +230,20 @@ def check_valid_sheetname(name)
230
230
  raise 'Invalid character []:*?/\\ in worksheet name: ' + name
231
231
  end
232
232
 
233
+ # Check that sheetname doesn't start or end with an apostrophe.
234
+ if name =~ /^'/ || name =~ /'$/
235
+ raise "Worksheet name #{name} cannot start or end with an "
236
+ end
237
+
238
+ # Check that sheetname isn't a reserved word.
239
+ if name =~ /history/i
240
+ raise "Worksheet name cannot be Excel reserved word 'History'"
241
+ end
242
+
233
243
  # Check that the worksheet name doesn't already exist since this is a fatal
234
244
  # error in Excel 97. The check must also exclude case insensitive matches.
235
245
  unless is_sheetname_uniq?(name)
236
- raise "Worksheet name '#{name}', with case ignored, is already used."
246
+ raise "apostropheWorksheet name '#{name}', with case ignored, is already used."
237
247
  end
238
248
  end
239
249
 
@@ -9,7 +9,7 @@ module Writexlsx
9
9
  # Used in conjunction with WriteXLSX.
10
10
  #
11
11
  # Copyright 2000-2012, John McNamara, jmcnamara@cpan.org
12
- # Converted to ruby by Hideo NAKAMURA, cxn03651@msj.biglobe.ne.jp
12
+ # Converted to ruby by Hideo NAKAMURA, nakamura.hideo@gmail.com
13
13
  #
14
14
  class Sparkline
15
15
  include Writexlsx::Utility
@@ -785,14 +785,14 @@ def params_to_font(params)
785
785
  #
786
786
  # Write the <c:txPr> element.
787
787
  #
788
- def write_tx_pr(horiz, font) # :nodoc:
788
+ def write_tx_pr(is_y_axis, font) # :nodoc:
789
789
  rotation = nil
790
790
  if font && font[:_rotation]
791
791
  rotation = font[:_rotation]
792
792
  end
793
793
  @writer.tag_elements('c:txPr') do
794
794
  # Write the a:bodyPr element.
795
- write_a_body_pr(rotation, horiz)
795
+ write_a_body_pr(rotation, is_y_axis)
796
796
  # Write the a:lstStyle element.
797
797
  write_a_lst_style
798
798
  # Write the a:p element.
@@ -803,11 +803,23 @@ def write_tx_pr(horiz, font) # :nodoc:
803
803
  #
804
804
  # Write the <a:bodyPr> element.
805
805
  #
806
- def write_a_body_pr(rot, horiz = nil) # :nodoc:
807
- rot = -5400000 if !rot && ptrue?(horiz)
806
+ def write_a_body_pr(rot, is_y_axis = nil) # :nodoc:
807
+ rot = -5400000 if !rot && ptrue?(is_y_axis)
808
808
  attributes = []
809
- attributes << ['rot', rot] if rot
810
- attributes << ['vert', 'horz'] if ptrue?(horiz)
809
+ if rot
810
+ if rot == 16_200_000
811
+ # 270 deg/stacked angle.
812
+ attributes << ['rot', 0]
813
+ attributes << ['vert', 'wordArtVert']
814
+ elsif rot == 16_260_000
815
+ # 271 deg/stacked angle.
816
+ attributes << ['rot', 0]
817
+ attributes << ['vert', 'eaVert']
818
+ else
819
+ attributes << ['rot', rot]
820
+ attributes << ['vert', 'horz']
821
+ end
822
+ end
811
823
 
812
824
  @writer.empty_tag('a:bodyPr', attributes)
813
825
  end
@@ -1 +1 @@
1
- WriteXLSX_VERSION = "1.00.0"
1
+ WriteXLSX_VERSION = "1.01.0"
@@ -1924,7 +1924,7 @@ def prepare_drawings #:nodoc:
1924
1924
  shape_count = sheet.shapes.size
1925
1925
  header_image_count = sheet.header_images.size
1926
1926
  footer_image_count = sheet.footer_images.size
1927
- has_drawing = false
1927
+ has_drawings = false
1928
1928
 
1929
1929
  # Check that some image or drawing needs to be processed.
1930
1930
  next if chart_count + image_count + shape_count + header_image_count + footer_image_count == 0
@@ -1932,7 +1932,7 @@ def prepare_drawings #:nodoc:
1932
1932
  # Don't increase the drawing_id header/footer images.
1933
1933
  if chart_count + image_count + shape_count > 0
1934
1934
  drawing_id += 1
1935
- has_drawing = true
1935
+ has_drawings = true
1936
1936
  end
1937
1937
 
1938
1938
  # Prepare the worksheet charts.
@@ -1981,9 +1981,9 @@ def prepare_drawings #:nodoc:
1981
1981
  name, type, position, x_dpi, y_dpi)
1982
1982
  end
1983
1983
 
1984
- if has_drawing
1985
- drawing = sheet.drawing
1986
- @drawings << drawing
1984
+ if has_drawings
1985
+ drawings = sheet.drawings
1986
+ @drawings << drawings
1987
1987
  end
1988
1988
  end
1989
1989
 
@@ -285,7 +285,7 @@ class Worksheet
285
285
  PADDING = 5 # :nodoc:
286
286
 
287
287
  attr_reader :index # :nodoc:
288
- attr_reader :charts, :images, :tables, :shapes, :drawing # :nodoc:
288
+ attr_reader :charts, :images, :tables, :shapes, :drawings # :nodoc:
289
289
  attr_reader :header_images, :footer_images # :nodoc:
290
290
  attr_reader :vml_drawing_links # :nodoc:
291
291
  attr_reader :vml_data_id # :nodoc:
@@ -365,6 +365,7 @@ def initialize(workbook, index, name) #:nodoc:
365
365
  @original_row_height = 15
366
366
  @default_row_height = 15
367
367
  @default_row_pixels = 20
368
+ @default_col_width = 8.43
368
369
  @default_col_pixels = 64
369
370
  @default_row_rezoed = 0
370
371
 
@@ -768,10 +769,10 @@ def set_column(*args)
768
769
 
769
770
  # Store the col sizes for use when calculating image vertices taking
770
771
  # hidden columns into account. Also store the column formats.
771
- width = 0 if ptrue?(hidden) # Set width to zero if hidden
772
+ width = @default_col_width unless width
772
773
 
773
774
  (firstcol .. lastcol).each do |col|
774
- @col_sizes[col] = width
775
+ @col_sizes[col] = [width, hidden]
775
776
  @col_formats[col] = format if format
776
777
  end
777
778
  end
@@ -2169,7 +2170,7 @@ def write_comment(*args)
2169
2170
  @has_vml = true
2170
2171
 
2171
2172
  # Process the properties of the cell comment.
2172
- @comments.add(Package::Comment.new(@workbook, self, row, col, string, options))
2173
+ @comments.add(@workbook, self, row, col, string, options)
2173
2174
  end
2174
2175
 
2175
2176
  #
@@ -2781,7 +2782,7 @@ def write_url(*args)
2781
2782
  store_hyperlink(row, col, hyperlink)
2782
2783
 
2783
2784
  if hyperlinks_count > 65_530
2784
- raise "URL '#{url}' added but number of URLS is over Excel's limit of 65,530 URLS per worksheet."
2785
+ raise "URL '#{url}' added but URL exceeds Excel's limit of 65,530 URLs per worksheet."
2785
2786
  end
2786
2787
 
2787
2788
  # Add the default URL format.
@@ -2990,13 +2991,25 @@ def write_date_time(*args)
2990
2991
  #
2991
2992
  def insert_chart(*args)
2992
2993
  # Check for a cell reference in A1 notation and substitute row and column.
2993
- row, col, chart, x_offset, y_offset, x_scale, y_scale = row_col_notation(args)
2994
+ row, col, chart, *options = row_col_notation(args)
2994
2995
  raise WriteXLSXInsufficientArgumentError if [row, col, chart].include?(nil)
2995
2996
 
2997
+ if options.first.class == Hash
2998
+ params = options.first
2999
+ x_offset = params[:x_offset]
3000
+ y_offset = params[:y_offset]
3001
+ x_scale = params[:x_scale]
3002
+ y_scale = params[:y_scale]
3003
+ anchor = params[:object_position]
3004
+
3005
+ else
3006
+ x_offset, y_offset, x_scale, y_scale, anchor = options
3007
+ end
2996
3008
  x_offset ||= 0
2997
3009
  y_offset ||= 0
2998
3010
  x_scale ||= 1
2999
3011
  y_scale ||= 1
3012
+ anchor ||= 1
3000
3013
 
3001
3014
  raise "Not a Chart object in insert_chart()" unless chart.is_a?(Chart) || chart.is_a?(Chartsheet)
3002
3015
  raise "Not a embedded style Chart object in insert_chart()" if chart.respond_to?(:embedded) && chart.embedded == 0
@@ -3014,61 +3027,36 @@ def insert_chart(*args)
3014
3027
  x_offset = chart.x_offset if ptrue?(chart.x_offset)
3015
3028
  y_offset = chart.y_offset if ptrue?(chart.y_offset)
3016
3029
 
3017
- @charts << [row, col, chart, x_offset, y_offset, x_scale, y_scale]
3030
+ @charts << [row, col, chart, x_offset, y_offset, x_scale, y_scale, anchor]
3018
3031
  end
3019
3032
 
3020
3033
  #
3021
3034
  # :call-seq:
3022
- # insert_image(row, column, filename, x=0, y=0, x_scale=1, y_scale=1)
3023
- #
3024
- # Partially supported. Currently only works for 96 dpi images.
3025
- #
3026
- # This method can be used to insert a image into a worksheet. The image
3027
- # can be in PNG, JPEG or BMP format. The x, y, x_scale and y_scale
3028
- # parameters are optional.
3029
- #
3030
- # worksheet1.insert_image('A1', 'ruby.bmp')
3031
- # worksheet2.insert_image('A1', '../images/ruby.bmp')
3032
- # worksheet3.insert_image('A1', '.c:\images\ruby.bmp')
3033
- #
3034
- # The parameters +x+ and +y+ can be used to specify an offset from the top
3035
- # left hand corner of the cell specified by +row+ and +column+. The offset
3036
- # values are in pixels.
3037
- #
3038
- # worksheet1.insert_image('A1', 'ruby.bmp', 32, 10)
3039
- #
3040
- # The offsets can be greater than the width or height of the underlying
3041
- # cell. This can be occasionally useful if you wish to align two or more
3042
- # images relative to the same cell.
3043
- #
3044
- # The parameters +x_scale+ and +y_scale+ can be used to scale the inserted
3045
- # image horizontally and vertically:
3046
- #
3047
- # # Scale the inserted image: width x 2.0, height x 0.8
3048
- # worksheet.insert_image('A1', 'perl.bmp', 0, 0, 2, 0.8)
3049
- #
3050
- # Note: you must call set_row() or set_column() before insert_image()
3051
- # if you wish to change the default dimensions of any of the rows or
3052
- # columns that the image occupies. The height of a row can also change
3053
- # if you use a font that is larger than the default. This in turn will
3054
- # affect the scaling of your image. To avoid this you should explicitly
3055
- # set the height of the row using set_row() if it contains a font size
3056
- # that will change the row height.
3057
- #
3058
- # BMP images must be 24 bit, true colour, bitmaps. In general it is
3059
- # best to avoid BMP images since they aren't compressed.
3035
+ # insert_image(row, column, filename, options)
3060
3036
  #
3061
3037
  def insert_image(*args)
3062
3038
  # Check for a cell reference in A1 notation and substitute row and column.
3063
- row, col, image, x_offset, y_offset, x_scale, y_scale = row_col_notation(args)
3039
+ row, col, image, *options = row_col_notation(args)
3064
3040
  raise WriteXLSXInsufficientArgumentError if [row, col, image].include?(nil)
3065
3041
 
3042
+ if options.first.class == Hash
3043
+ # Newer hash bashed options
3044
+ params = options.first
3045
+ x_offset = params[:x_offset]
3046
+ y_offset = params[:y_offset]
3047
+ x_scale = params[:x_scale]
3048
+ y_scale = params[:y_scale]
3049
+ anchor = params[:object_position]
3050
+ else
3051
+ x_offset, y_offset, x_scale, y_scale, anchor = options
3052
+ end
3066
3053
  x_offset ||= 0
3067
3054
  y_offset ||= 0
3068
3055
  x_scale ||= 1
3069
3056
  y_scale ||= 1
3057
+ anchor ||= 2
3070
3058
 
3071
- @images << [row, col, image, x_offset, y_offset, x_scale, y_scale]
3059
+ @images << [row, col, image, x_offset, y_offset, x_scale, y_scale, anchor]
3072
3060
  end
3073
3061
 
3074
3062
  #
@@ -3306,10 +3294,8 @@ def set_row(*args)
3306
3294
  # Store the row change to allow optimisations.
3307
3295
  @row_size_changed = true
3308
3296
 
3309
- height = 0 if ptrue?(hidden)
3310
-
3311
3297
  # Store the row sizes for use when calculating image vertices.
3312
- @row_sizes[row] = height
3298
+ @row_sizes[row] = [height, hidden]
3313
3299
  end
3314
3300
 
3315
3301
  #
@@ -5724,7 +5710,7 @@ def set_external_comment_links(comment_id) # :nodoc:
5724
5710
  def prepare_chart(index, chart_id, drawing_id) # :nodoc:
5725
5711
  drawing_type = 1
5726
5712
 
5727
- row, col, chart, x_offset, y_offset, x_scale, y_scale = @charts[index]
5713
+ row, col, chart, x_offset, y_offset, x_scale, y_scale, anchor = @charts[index]
5728
5714
  chart.id = chart_id - 1
5729
5715
  x_scale ||= 0
5730
5716
  y_scale ||= 0
@@ -5736,22 +5722,21 @@ def prepare_chart(index, chart_id, drawing_id) # :nodoc:
5736
5722
  width = (0.5 + (width * x_scale)).to_i
5737
5723
  height = (0.5 + (height * y_scale)).to_i
5738
5724
 
5739
- dimensions = position_object_emus(col, row, x_offset, y_offset, width, height)
5725
+ dimensions = position_object_emus(col, row, x_offset, y_offset, width, height, anchor)
5740
5726
 
5741
5727
  # Set the chart name for the embedded object if it has been specified.
5742
5728
  name = chart.name
5743
5729
 
5744
5730
  # Create a Drawing object to use with worksheet unless one already exists.
5745
- if !drawing?
5746
- drawing = Drawing.new
5747
- drawing.add_drawing_object(drawing_type, dimensions, 0, 0, name)
5748
- drawing.embedded = 1
5749
-
5750
- @drawing = drawing
5731
+ drawing = Drawing.new(drawing_type, dimensions, 0, 0, name, nil, anchor)
5732
+ if !drawings?
5733
+ @drawings = Drawings.new
5734
+ @drawings.add_drawing_object(drawing)
5735
+ @drawings.embedded = 1
5751
5736
 
5752
5737
  @external_drawing_links << ['/drawing', "../drawings/drawing#{drawing_id}.xml" ]
5753
5738
  else
5754
- @drawing.add_drawing_object(drawing_type, dimensions, 0, 0, name)
5739
+ @drawings.add_drawing_object(drawing)
5755
5740
  end
5756
5741
  @drawing_links << ['/chart', "../charts/chart#{chart_id}.xml"]
5757
5742
  end
@@ -5822,6 +5807,10 @@ def get_range_data(row_start, col_start, row_end, col_end) # :nodoc:
5822
5807
  # The values of col_start and row_start are passed in from the calling
5823
5808
  # function. The values of col_end and row_end are calculated by subtracting
5824
5809
  # the width and height of the object from the width and height of the
5810
+ # The anchor/object position defines how images are scaled for hidden rows and
5811
+ # columns. For option 1 "Move and size with cells" the size of the hidden
5812
+ # row/column is subtracted from the image.
5813
+ #
5825
5814
  # underlying cells.
5826
5815
  #
5827
5816
  # col_start # Col containing upper left corner of object.
@@ -5834,7 +5823,7 @@ def get_range_data(row_start, col_start, row_end, col_end) # :nodoc:
5834
5823
  # y2 # Distance to bottom of object.
5835
5824
  # width # Width of object frame.
5836
5825
  # height # Height of object frame.
5837
- def position_object_pixels(col_start, row_start, x1, y1, width, height) #:nodoc:
5826
+ def position_object_pixels(col_start, row_start, x1, y1, width, height, anchor = nil) #:nodoc:
5838
5827
  # Adjust start column for negative offsets.
5839
5828
  while x1 < 0 && col_start > 0
5840
5829
  x1 += size_col(col_start - 1)
@@ -5853,7 +5842,7 @@ def position_object_pixels(col_start, row_start, x1, y1, width, height) #:nodoc:
5853
5842
 
5854
5843
  # Calculate the absolute x offset of the top-left vertex.
5855
5844
  if @col_size_changed
5856
- x_abs = (0 .. col_start-1).inject(0) {|sum, col| sum += size_col(col)}
5845
+ x_abs = (0 .. col_start-1).inject(0) {|sum, col| sum += size_col(col, anchor)}
5857
5846
  else
5858
5847
  # Optimisation for when the column widths haven't changed.
5859
5848
  x_abs = @default_col_pixels * col_start
@@ -5863,7 +5852,7 @@ def position_object_pixels(col_start, row_start, x1, y1, width, height) #:nodoc:
5863
5852
  # Calculate the absolute y offset of the top-left vertex.
5864
5853
  # Store the column change to allow optimisations.
5865
5854
  if @row_size_changed
5866
- y_abs = (0 .. row_start-1).inject(0) {|sum, row| sum += size_row(row)}
5855
+ y_abs = (0 .. row_start-1).inject(0) {|sum, row| sum += size_row(row, anchor)}
5867
5856
  else
5868
5857
  # Optimisation for when the row heights haven't changed.
5869
5858
  y_abs = @default_row_pixels * row_start
@@ -5872,12 +5861,18 @@ def position_object_pixels(col_start, row_start, x1, y1, width, height) #:nodoc:
5872
5861
 
5873
5862
  # Adjust start column for offsets that are greater than the col width.
5874
5863
  if size_col(col_start) > 0
5875
- x1, col_start = adjust_column_offset(x1, col_start)
5864
+ while x1 >= size_col(col_start)
5865
+ x1 -= size_col(col_start)
5866
+ col_start += 1
5867
+ end
5876
5868
  end
5877
5869
 
5878
5870
  # Adjust start row for offsets that are greater than the row height.
5879
5871
  if size_row(row_start) > 0
5880
- y1, row_start = adjust_row_offset(y1, row_start)
5872
+ while y1 >= size_row(row_start)
5873
+ y1 -= size_row(row_start)
5874
+ row_start += 1
5875
+ end
5881
5876
  end
5882
5877
 
5883
5878
  # Initialise end cell to the same as the start cell.
@@ -5888,10 +5883,16 @@ def position_object_pixels(col_start, row_start, x1, y1, width, height) #:nodoc:
5888
5883
  height += y1 if size_row(row_start) > 0
5889
5884
 
5890
5885
  # Subtract the underlying cell widths to find the end cell of the object.
5891
- width, col_end = adjust_column_offset(width, col_end)
5886
+ while width >= size_col(col_end, anchor)
5887
+ width -= size_col(col_end, anchor)
5888
+ col_end += 1
5889
+ end
5892
5890
 
5893
5891
  # Subtract the underlying cell heights to find the end cell of the object.
5894
- height, row_end = adjust_row_offset(height, row_end)
5892
+ while height >= size_row(row_end, anchor)
5893
+ height -= size_row(row_end, anchor)
5894
+ row_end += 1
5895
+ end
5895
5896
 
5896
5897
  # The end vertices are whatever is left from the width and height.
5897
5898
  x2 = width
@@ -6351,32 +6352,16 @@ def sort_pagebreaks(*args) #:nodoc:
6351
6352
  end
6352
6353
  end
6353
6354
 
6354
- def adjust_column_offset(x, column)
6355
- while x >= size_col(column)
6356
- x -= size_col(column)
6357
- column += 1
6358
- end
6359
- [x, column]
6360
- end
6361
-
6362
- def adjust_row_offset(y, row)
6363
- while y >= size_row(row)
6364
- y -= size_row(row)
6365
- row += 1
6366
- end
6367
- [y, row]
6368
- end
6369
-
6370
6355
  #
6371
6356
  # Calculate the vertices that define the position of a graphical object within
6372
6357
  # the worksheet in EMUs.
6373
6358
  #
6374
6359
  # The vertices are expressed as English Metric Units (EMUs). There are 12,700
6375
- # EMUs per point. Therefore, 12,700 * 3 /4 = 9,525 EMUs per pixel.
6360
+ # EMUs per point. Therefore, 12,700 * 3 /4 = 9,525 EMUs per el.
6376
6361
  #
6377
- def position_object_emus(col_start, row_start, x1, y1, width, height, x_dpi = 96, y_dpi = 96) #:nodoc:
6362
+ def position_object_emus(col_start, row_start, x1, y1, width, height, anchor = nil) #:nodoc:
6378
6363
  col_start, row_start, x1, y1, col_end, row_end, x2, y2, x_abs, y_abs =
6379
- position_object_pixels(col_start, row_start, x1, y1, width, height)
6364
+ position_object_pixels(col_start, row_start, x1, y1, width, height, anchor)
6380
6365
 
6381
6366
  # Convert the pixel values to EMUs. See above.
6382
6367
  x1 = (0.5 + 9_525 * x1).to_i
@@ -6392,15 +6377,16 @@ def position_object_emus(col_start, row_start, x1, y1, width, height, x_dpi = 96
6392
6377
  #
6393
6378
  # Convert the width of a cell from user's units to pixels. Excel rounds the
6394
6379
  # column width to the nearest pixel. If the width hasn't been set by the user
6395
- # we use the default value. If the column is hidden it has a value of zero.
6380
+ # we use the default value. A hidden column is treated as having a width of
6381
+ # zero unless it has the special "object_position" of 4 (size with cells).
6396
6382
  #
6397
- def size_col(col) #:nodoc:
6383
+ def size_col(col, anchor = 0) #:nodoc:
6398
6384
  # Look up the cell value to see if it has been changed.
6399
6385
  if @col_sizes[col]
6400
- width = @col_sizes[col]
6386
+ width, hidden = @col_sizes[col]
6401
6387
 
6402
6388
  # Convert to pixels.
6403
- if width == 0
6389
+ if hidden == 1 && anchor != 4
6404
6390
  pixels = 0
6405
6391
  elsif width < 1
6406
6392
  pixels = (width * (MAX_DIGIT_WIDTH + PADDING) + 0.5).to_i
@@ -6415,15 +6401,16 @@ def size_col(col) #:nodoc:
6415
6401
 
6416
6402
  #
6417
6403
  # Convert the height of a cell from user's units to pixels. If the height
6418
- # hasn't been set by the user we use the default value. If the row is hidden
6419
- # it has a value of zero.
6404
+ # hasn't been set by the user we use the default value. A hidden row is
6405
+ # treated as having a height of zero unless it has the special
6406
+ # "object_position" of 4 (size with cells).
6420
6407
  #
6421
- def size_row(row) #:nodoc:
6408
+ def size_row(row, anchor = 0) #:nodoc:
6422
6409
  # Look up the cell value to see if it has been changed
6423
6410
  if @row_sizes[row]
6424
- height = @row_sizes[row]
6411
+ height, hidden = @row_sizes[row]
6425
6412
 
6426
- if height == 0
6413
+ if hidden == 1 && anchor != 4
6427
6414
  pixels = 0
6428
6415
  else
6429
6416
  pixels = (4 / 3.0 * height).to_i
@@ -6441,9 +6428,8 @@ def prepare_image(index, image_id, drawing_id, width, height, name, image_type,
6441
6428
  x_dpi ||= 96
6442
6429
  y_dpi ||= 96
6443
6430
  drawing_type = 2
6444
- drawing
6445
6431
 
6446
- row, col, image, x_offset, y_offset, x_scale, y_scale = @images[index]
6432
+ row, col, image, x_offset, y_offset, x_scale, y_scale, anchor = @images[index]
6447
6433
 
6448
6434
  width *= x_scale
6449
6435
  height *= y_scale
@@ -6451,24 +6437,25 @@ def prepare_image(index, image_id, drawing_id, width, height, name, image_type,
6451
6437
  width *= 96.0 / x_dpi
6452
6438
  height *= 96.0 / y_dpi
6453
6439
 
6454
- dimensions = position_object_emus(col, row, x_offset, y_offset, width, height)
6440
+ dimensions = position_object_emus(col, row, x_offset, y_offset, width, height, anchor)
6455
6441
 
6456
6442
  # Convert from pixels to emus.
6457
6443
  width = (0.5 + (width * 9_525)).to_i
6458
6444
  height = (0.5 + (height * 9_525)).to_i
6459
6445
 
6460
6446
  # Create a Drawing object to use with worksheet unless one already exists.
6461
- if !drawing?
6462
- drawing = Drawing.new
6463
- drawing.embedded = 1
6447
+ drawing = Drawing.new(drawing_type, dimensions, width, height, name, nil, anchor)
6448
+ if !drawings?
6449
+ drawings = Drawings.new
6450
+ drawings.embedded = 1
6464
6451
 
6465
- @drawing = drawing
6452
+ @drawings = drawings
6466
6453
 
6467
6454
  @external_drawing_links << ['/drawing', "../drawings/drawing#{drawing_id}.xml"]
6468
6455
  else
6469
- drawing = @drawing
6456
+ drawings = @drawings
6470
6457
  end
6471
- drawing.add_drawing_object(drawing_type, dimensions, width, height, name)
6458
+ drawings.add_drawing_object(drawing)
6472
6459
 
6473
6460
  @drawing_links << ['/image', "../media/image#{image_id}.#{image_type}"]
6474
6461
  end
@@ -6523,16 +6510,16 @@ def prepare_header_image(image_id, width, height, name, image_type, position, x_
6523
6510
  #
6524
6511
  def insert_shape(*args)
6525
6512
  # Check for a cell reference in A1 notation and substitute row and column.
6526
- row_start, column_start, shape, x_offset, y_offset, x_scale, y_scale =
6513
+ row_start, column_start, shape, x_offset, y_offset, x_scale, y_scale, anchor =
6527
6514
  row_col_notation(args)
6528
6515
  if [row_start, column_start, shape].include?(nil)
6529
6516
  raise "Insufficient arguments in insert_shape()"
6530
6517
  end
6531
6518
 
6532
6519
  shape.set_position(
6533
- row_start, column_start, x_offset, y_offset,
6534
- x_scale, y_scale
6535
- )
6520
+ row_start, column_start, x_offset, y_offset,
6521
+ x_scale, y_scale, anchor
6522
+ )
6536
6523
  # Assign a shape ID.
6537
6524
  while true
6538
6525
  id = shape.id || 0
@@ -6576,9 +6563,9 @@ def prepare_shape(index, drawing_id)
6576
6563
  shape = @shapes[index]
6577
6564
 
6578
6565
  # Create a Drawing object to use with worksheet unless one already exists.
6579
- unless drawing?
6580
- @drawing = Drawing.new
6581
- @drawing.embedded = 1
6566
+ unless drawings?
6567
+ @drawings = Drawings.new
6568
+ @drawings.embedded = 1
6582
6569
  @external_drawing_links << ['/drawing', "../drawings/drawing#{drawing_id}.xml"]
6583
6570
  @has_shapes = true
6584
6571
  end
@@ -6588,13 +6575,14 @@ def prepare_shape(index, drawing_id)
6588
6575
  shape.calc_position_emus(self)
6589
6576
 
6590
6577
  drawing_type = 3
6591
- drawing.add_drawing_object(drawing_type, shape.dimensions, shape.name, shape)
6578
+ drawing = Drawing.new(drawing_type, shape.dimensions, shape.width_emu, shape.height_emu, shape.name, shape, shape.anchor)
6579
+ drawings.add_drawing_object(drawing)
6592
6580
  end
6593
6581
  public :prepare_shape
6594
6582
 
6595
6583
  #
6596
6584
  # This method handles the parameters passed to insert_button as well as
6597
- # calculating the comment object position and vertices.
6585
+ # calculating the button object position and vertices.
6598
6586
  #
6599
6587
  def button_params(row, col, params)
6600
6588
  button = Writexlsx::Package::Button.new
@@ -6623,7 +6611,7 @@ def button_params(row, col, params)
6623
6611
  params[:x_offset] = 0 if !params[:x_offset]
6624
6612
  params[:y_offset] = 0 if !params[:y_offset]
6625
6613
 
6626
- # Scale the size of the comment box if required.
6614
+ # Scale the size of the button box if required.
6627
6615
  if params[:x_scale]
6628
6616
  params[:width] = params[:width] * params[:x_scale]
6629
6617
  end
@@ -6638,15 +6626,15 @@ def button_params(row, col, params)
6638
6626
  params[:start_row] = row
6639
6627
  params[:start_col] = col
6640
6628
 
6641
- # Calculate the positions of comment object.
6629
+ # Calculate the positions of button object.
6642
6630
  vertices = position_object_pixels(
6643
- params[:start_col],
6644
- params[:start_row],
6645
- params[:x_offset],
6646
- params[:y_offset],
6647
- params[:width],
6648
- params[:height]
6649
- )
6631
+ params[:start_col],
6632
+ params[:start_row],
6633
+ params[:x_offset],
6634
+ params[:y_offset],
6635
+ params[:width],
6636
+ params[:height]
6637
+ )
6650
6638
 
6651
6639
  # Add the width and height for VML.
6652
6640
  vertices << [params[:width], params[:height]]
@@ -6886,7 +6874,7 @@ def col_info_attributes(args)
6886
6874
  custom_width = false if width.nil? && hidden == 0
6887
6875
  custom_width = false if width == 8.43
6888
6876
 
6889
- width = hidden == 0 ? 8.43 : 0 unless width
6877
+ width = hidden == 0 ? @default_col_width : 0 unless width
6890
6878
 
6891
6879
  # Convert column width from user units to character width.
6892
6880
  if width && width < 1
@@ -7496,7 +7484,7 @@ def write_sheet_protection #:nodoc:
7496
7484
  # Write the <drawing> elements.
7497
7485
  #
7498
7486
  def write_drawings #:nodoc:
7499
- increment_rel_id_and_write_r_id('drawing') if drawing?
7487
+ increment_rel_id_and_write_r_id('drawing') if drawings?
7500
7488
  end
7501
7489
 
7502
7490
  #
@@ -7974,8 +7962,8 @@ def autofilter_ref? #:nodoc:
7974
7962
  !!@autofilter_ref
7975
7963
  end
7976
7964
 
7977
- def drawing? #:nodoc:
7978
- !!@drawing
7965
+ def drawings? #:nodoc:
7966
+ !!@drawings
7979
7967
  end
7980
7968
 
7981
7969
  def remove_white_space(margin) #:nodoc: