write_xlsx 1.00.0 → 1.01.0

Sign up to get free protection for your applications and to get access to all the features.
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: