ea 0.6.123 → 0.6.125

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d897b1e2165c9993420958c081ee3e2eedebbfbb8ac4db1ea8f160fd45913a3d
4
- data.tar.gz: 667e5cce39c543c97f96fd7b64c994d72808daf3bf6a875ae112e0efe4b2623b
3
+ metadata.gz: ee64290319fb525469230eeb6d6f1fc2b923a8a2d82115c6f297d98d0d90e10b
4
+ data.tar.gz: 76d8ead072a4ea88a2429cc506ecc410a62cd5755688b53d88cf5df41866fbc7
5
5
  SHA512:
6
- metadata.gz: e8789c4187a4c72534f2e4d17f1caf650e7da1748aa08bed49764fa6fde0dafdfc1bf8c6811ab7a33e31b6da1ffe0a71397b6ca60b1a8c2e7ee0e65a4798368d
7
- data.tar.gz: 37bf77d8c14e921888081ee961506f835b5cd0de1bb28de790d5ba848003915922e83c83e2b29d6db0f58141f25dc1d643059f642950ee6cd2028da87d42b42f
6
+ metadata.gz: 43f49df97683830c845d3124dbc36de402fa482c3c90362477d594087e5c8267083aae48e81bdfd0c0a341a4a71b729b75d7ba26245dc2e9001895333237dc2b
7
+ data.tar.gz: fe1b7a4c60545649fbabb1d24312959ba1a74f0c73b9e299d3518c0e7c4b7ae166843481c12a523398b704805c999fbb1d692bfb051faf53b6603e08299069a4
@@ -21,6 +21,7 @@ module Ea
21
21
 
22
22
  attribute :title, :string, default: -> { DEFAULT_TITLE }
23
23
  attribute :heading_size, :integer
24
+ attribute :heading_family, :string
24
25
  attribute :font_color, :integer, default: -> { DEFAULT_FONT_COLOR }
25
26
  attribute :background_color, :integer, default: -> { DEFAULT_BACKGROUND_COLOR }
26
27
  attribute :border_color, :integer, default: -> { DEFAULT_BORDER_COLOR }
@@ -32,6 +33,7 @@ module Ea
32
33
  map "name", to: :name
33
34
  map "title", to: :title
34
35
  map "headingSize", to: :heading_size
36
+ map "headingFamily", to: :heading_family
35
37
  map "fontColor", to: :font_color
36
38
  map "backgroundColor", to: :background_color
37
39
  map "borderColor", to: :border_color
@@ -12,6 +12,7 @@ module Ea
12
12
  # Returns nil when no matching xref exists (the Text element
13
13
  # is not a legend — caller should render it as a plain note).
14
14
  class LegendBuilder
15
+ DEFAULT_HEADING_FAMILY = "Cambria"
15
16
  LEGEND_XREF_NAME = "CustomProperties"
16
17
  LEGEND_TYPE_OBJECT_STYLE = "LEGEND_OBJECTSTYLE"
17
18
  LEGEND_TYPE_STYLE_SETTINGS = "LEGEND_STYLE_SETTINGS"
@@ -77,6 +78,7 @@ module Ea
77
78
  Ea::Model::Legend.new(
78
79
  title: style["TITLE"] || Ea::Model::Legend::DEFAULT_TITLE,
79
80
  heading_size: int_or_nil(style["HEADINGSIZE"]),
81
+ heading_family: DEFAULT_HEADING_FAMILY,
80
82
  font_color: int_or(style["FONTCOLOR"],
81
83
  Ea::Model::Legend::DEFAULT_FONT_COLOR),
82
84
  background_color: int_or(style["BACKGROUNDCOLOR"],
@@ -256,12 +256,14 @@ module Ea
256
256
  end
257
257
  private_class_method :default_model_connector?
258
258
 
259
- # A thin straight Generalization/Aggregation/Association between two elements
260
- # drawn with a 2px border stops on the outer edge of those borders.
259
+ # Thin connectors between explicitly bordered elements stop on the outer
260
+ # edge of their 2px borders, including package imports.
261
261
  def bordered_outline?(connector, diagram, refs, bounds)
262
262
  style = connector.style.to_h
263
263
  return false unless style[:lwidth] == "0" && !style[:tree]
264
- return false unless %w[Generalization Aggregation Association Dependency].include?(connector.connector_type)
264
+ return false unless %w[Generalization Aggregation Association Dependency Package].include?(
265
+ connector.connector_type
266
+ )
265
267
  return false unless bounds.all? { |box| box.width.positive? && box.height.positive? }
266
268
 
267
269
  ends = [[refs.first, style[:soid]], [refs.last, style[:eoid]]]
@@ -40,6 +40,7 @@ module Ea
40
40
  attr_line_offset: 6,
41
41
  attr_first_offset: 7,
42
42
  attr_group_lead: 0,
43
+ compact_standard_operations: false,
43
44
  family: nil, size_unit: "pt", logical_height: nil,
44
45
  header_ghost: false,
45
46
  header_ghost_tight: false)
@@ -61,6 +62,7 @@ module Ea
61
62
  @attr_line_offset = attr_line_offset
62
63
  @attr_first_offset = attr_first_offset
63
64
  @attr_group_lead = attr_group_lead
65
+ @compact_standard_operations = compact_standard_operations
64
66
  @header_ghost = header_ghost
65
67
  @header_ghost_tight = header_ghost_tight
66
68
  end
@@ -137,24 +139,29 @@ module Ea
137
139
  end
138
140
 
139
141
  def op_divider_y
142
+ return attr_bottom_y + line_height(attr_line_offset || 6) / 2.0 if compact_operation_spacing?
143
+
140
144
  attr_bottom_y + size + 5
141
145
  end
142
146
 
143
- # EA's op block: first row 21 below the last attribute row
144
- # (9pt... 7pt: attr_bottom + 21), uniform 13px pitch across
145
- # attrs AND ops (6D4C665D: attrs ..520, ops 541..658 step 13).
146
- # Attribute-empty boxes anchor on the divider instead:
147
- # first op at divider + 14 (001A64C1: EA ops 104 vs our
148
- # 125 when attrs were absent).
147
+ # Compact standard classes end attributes with a half row cell;
148
+ # operations then use the same inset as an attribute-empty box.
149
149
  def op_first_y
150
150
  return nil unless op_lines_count&.positive?
151
151
 
152
- if attr_lines_count.to_i.positive?
153
- attr_bottom_y + size + 14
154
- else
155
- divider_y + size + 7
156
- end
152
+ anchor = if attr_lines_count.to_i.positive?
153
+ compact_operation_spacing? ? op_divider_y : attr_bottom_y + 7
154
+ else
155
+ divider_y
156
+ end
157
+ anchor + size + 7
158
+ end
159
+
160
+ def compact_operation_spacing?
161
+ @compact_standard_operations && attr_lines_count.to_i.positive? &&
162
+ Ea::Fonts::Metrics.compact_compartment_font?(size, family: @family, unit: @size_unit)
157
163
  end
164
+ private :compact_operation_spacing?
158
165
 
159
166
  def op_bottom_y
160
167
  return op_divider_y unless op_lines_count&.positive?
@@ -126,10 +126,16 @@ module Ea
126
126
 
127
127
  def item_label(item, index)
128
128
  x = bounds.x + ICON_X_OFFSET + ICON_LABEL_GAP
129
- y = item_top_y(index) + LABEL_BASELINE_FROM_ICON_TOP
129
+ y = item_top_y(index) + item_label_baseline
130
130
  build_text(item.name, x: x, y: y, size: item_font_size, weight: 0)
131
131
  end
132
132
 
133
+ def item_label_baseline
134
+ return LABEL_BASELINE_FROM_ICON_TOP unless (item_font[:unit] || "pt") == "pt"
135
+
136
+ item_font[:logical_height] || LABEL_BASELINE_FROM_ICON_TOP
137
+ end
138
+
133
139
  def title_text
134
140
  x = title_x
135
141
  y = bounds.y + TITLE_Y_OFFSET
@@ -152,8 +158,8 @@ module Ea
152
158
 
153
159
  # Real font metrics when available; legacy per-char
154
160
  # estimate otherwise (families without metric tables).
155
- def estimated_width(text, size, weight: nil, logical_height: nil)
156
- measured = Ea::Fonts::Metrics.text_length(text, size, family: family, weight: weight,
161
+ def estimated_width(text, size, weight: nil, logical_height: nil, text_family: family)
162
+ measured = Ea::Fonts::Metrics.text_length(text, size, family: text_family, weight: weight,
157
163
  logical_height: logical_height)
158
164
  return measured if measured
159
165
 
@@ -186,7 +192,11 @@ module Ea
186
192
  end
187
193
 
188
194
  def title_text_width
189
- estimated_width(legend.title, title_font_size, weight: 700)
195
+ estimated_width(legend.title, title_font_size, weight: 700, text_family: heading_family)
196
+ end
197
+
198
+ def heading_family
199
+ legend.heading_family || family
190
200
  end
191
201
 
192
202
  def build_text(content, x:, y:, size:, weight:)
@@ -194,7 +204,7 @@ module Ea
194
204
  size_unit = weight.zero? ? (item_font[:unit] || "pt") : "pt"
195
205
  TextRenderer.new(
196
206
  content: content.to_s, x: tx, y: ty,
197
- family: family, size: size, size_unit: size_unit,
207
+ family: weight.zero? ? family : heading_family, size: size, size_unit: size_unit,
198
208
  weight: weight, fill: label_fill, logical_height: weight.zero? ? item_font[:logical_height] : nil
199
209
  ).to_svg
200
210
  end
@@ -332,8 +332,22 @@ module Ea
332
332
  constraints_count: 0, marker_count: 0,
333
333
  enum_literals_count: 0,
334
334
  attr_group_lead: 0, family: nil, size_unit: "pt", logical_height: nil)
335
+ divider_offset = divider_offset_for(header_lines, classifier)
336
+ attr_first_offset = attr_first_offset_for(attr_lines)
337
+ compact_standard = compact_header_offsets?(
338
+ classifier, header_lines, size,
339
+ family: family, size_unit: size_unit, logical_height: logical_height,
340
+ marker_count: marker_count, enum_literals_count: enum_literals_count,
341
+ divider_offset: divider_offset, attr_first_offset: attr_first_offset
342
+ )
343
+ if compact_standard
344
+ divider_offset = 7
345
+ # Attribute baselines retain their anchor when the divider moves up.
346
+ attr_first_offset = 8
347
+ end
335
348
  CompartmentGeometry.new(bounds: bounds, size: size, family: family,
336
349
  size_unit: size_unit, logical_height: logical_height,
350
+ compact_standard_operations: compact_standard,
337
351
  header_ghost: header_lines.any? &&
338
352
  %i[italic italic_tight].include?(header_lines.first.last),
339
353
  header_ghost_tight: Element::HeaderLines.parent_ghost_gap(header_lines) == 3,
@@ -346,12 +360,21 @@ module Ea
346
360
  enum_literals_count: enum_literals_count,
347
361
  header_top_padding: header_padding_for(header_lines, classifier),
348
362
  header_line_offset: theme.compartments.header_line_offset,
349
- divider_offset: divider_offset_for(header_lines, classifier),
363
+ divider_offset: divider_offset,
350
364
  attr_line_offset: theme.compartments.attr_line_offset,
351
- attr_first_offset: attr_first_offset_for(attr_lines),
365
+ attr_first_offset: attr_first_offset,
352
366
  attr_group_lead: attr_group_lead)
353
367
  end
354
368
 
369
+ def compact_header_offsets?(classifier, header_lines, size, **options)
370
+ classifier.is_a?(Ea::Model::Klass) &&
371
+ Ea::Fonts::Metrics.compact_compartment_font?(size, family: options[:family], unit: options[:size_unit]) &&
372
+ !%i[italic italic_tight].include?(header_lines.dig(0, 1)) &&
373
+ options.values_at(:logical_height, :marker_count, :enum_literals_count,
374
+ :divider_offset, :attr_first_offset) == [nil, 0, 0, 8, 7] &&
375
+ theme.compartments.header_line_offset == 6 && theme.compartments.attr_line_offset == 6
376
+ end
377
+
355
378
  # EA seats a stereotype line 3px higher than a bare class name
356
379
  # (first baseline +16 vs +19 at 7pt) - and Enumeration /
357
380
  # Interface elements seat their stereotype 3px higher still
data/lib/ea/version.rb CHANGED
@@ -4,5 +4,5 @@ module Ea
4
4
  # Gem release version. Extracted to its own file so the
5
5
  # `gem-release` tool's `gem bump` can find and update it via the
6
6
  # standard `lib/<gem>/version.rb` convention.
7
- VERSION = "0.6.123"
7
+ VERSION = "0.6.125"
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.123
4
+ version: 0.6.125
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.