ea 0.6.96 → 0.6.97

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: 3b98c8ee8bf786f5160291763db47b38d8213a029ef4d647df1d73c386551dba
4
- data.tar.gz: 3f0ee88fdb07d831f70e1ec51f634048140887a5231baa3dc0eea778a7f60d7a
3
+ metadata.gz: c2ca3f0fd4381aec39af89849d601c85defa496b697f1fe625558c8a210aef64
4
+ data.tar.gz: adbc3773a202f06ad7327ace0fbea64daacea45a4719afb28959332673dafdcd
5
5
  SHA512:
6
- metadata.gz: f0297306864b343dc4bdd5cae1c6cdaabeb7a5bb043cc592c76f11c5b42cfce4e7895bbfb3e92c51a263072203ca7e46b5eb3640633856474afbdc22798db2ba
7
- data.tar.gz: de6096010a2802088ea9d8cee6fa9105c1b6622f4de8b89274668a5231645fd19727ad7633c74db66fbc6be04f70009f0d4d270f8ba4440189ff282f168d1313
6
+ metadata.gz: 99b878a17d58444e251964011cf2af59d46459223e657b8ffbf1a4602dc572af56e594bedd05c321cec0502d91e654cdd013d5b408277027d1c4f41c65885d3f
7
+ data.tar.gz: 73ef9107ec26ea7b60f7c9e5d00b7fa09b4d08b10842345c589a75dfd13a62b553287b95b0ad1b71e0c45fc032ab30ff1299fecb03e2a3abac69027a69180e97
@@ -0,0 +1,8 @@
1
+ id: "39"
2
+ name: EA theme 39 connector labels
3
+ font:
4
+ unit: px
5
+ label_font:
6
+ family: Cambria
7
+ size: 7
8
+ unit: pt
@@ -8,6 +8,78 @@ module Ea
8
8
  module Routing
9
9
  private
10
10
 
11
+ # Stored SY/EY use mathematical Y; ray origins use screen Y.
12
+ # Computed-jog origins are already normalized to their derived ports.
13
+ def correct_stored_ray_origins(model, link_row, diagram_row, geom, context)
14
+ return model if context
15
+ return model unless stored_ray_candidate?(model, link_row, geom)
16
+
17
+ source, target = stored_ray_boxes(link_row, diagram_row)
18
+ return model unless stored_ray_gap?(source, target, model.style[:mode], geom[:edge])
19
+
20
+ set_stored_ray_origins(model, source, target, geom)
21
+ end
22
+
23
+ def stored_ray_boxes(link_row, diagram_row)
24
+ connector = database.find_connector(link_row.connectorid)
25
+ [source_placement_for(connector, diagram_row),
26
+ target_placement_for(connector, diagram_row)].map { |placement| bounds_from_rect(placement) }
27
+ end
28
+
29
+ def set_stored_ray_origins(model, source, target, geom)
30
+ model.source_anchor = stored_ray_origin(source, geom[:sx], geom[:sy])
31
+ model.target_anchor = stored_ray_origin(target, geom[:ex], geom[:ey])
32
+ model
33
+ end
34
+
35
+ def stored_ray_candidate?(model, link_row, geom)
36
+ %w[Generalization Aggregation].include?(model.connector_type) &&
37
+ model.waypoints.size == 2 && stored_ray_style?(model.style, link_row) &&
38
+ stored_ray_geometry?(model, geom) && !normalized_port_anchors?(model)
39
+ end
40
+
41
+ def stored_ray_style?(style, link_row)
42
+ %w[1 3].include?(style[:mode]) && !style[:tree] &&
43
+ (style[:mode] == "1" || link_row.path.to_s.empty?)
44
+ end
45
+
46
+ def stored_ray_geometry?(model, geom)
47
+ model.has_geometry_offsets && model.source_port && model.target_port &&
48
+ (!geom[:sy].to_i.zero? || !geom[:ey].to_i.zero?)
49
+ end
50
+
51
+ def normalized_port_anchors?(model)
52
+ same_port_anchor?(model.source_anchor, model.source_port) &&
53
+ same_port_anchor?(model.target_anchor, model.target_port)
54
+ end
55
+
56
+ def same_port_anchor?(anchor, port)
57
+ anchor.x == port.x && anchor.y == port.y
58
+ end
59
+
60
+ def stored_ray_gap?(source, target, mode, edge)
61
+ return horizontal_ray_gap?(source, target) || vertical_ray_gap?(source, target) if mode == "1"
62
+
63
+ if edge == 1
64
+ target.y + target.height < source.y
65
+ elsif edge == 4
66
+ target.x + target.width < source.x
67
+ end
68
+ end
69
+
70
+ def horizontal_ray_gap?(source, target)
71
+ source.x + source.width < target.x || target.x + target.width < source.x
72
+ end
73
+
74
+ def vertical_ray_gap?(source, target)
75
+ source.y + source.height < target.y || target.y + target.height < source.y
76
+ end
77
+
78
+ def stored_ray_origin(bounds, x_offset, y_offset)
79
+ Ea::Model::Point.new(x: bounds.x + bounds.width / 2 + x_offset.to_i,
80
+ y: bounds.y + bounds.height / 2 - y_offset.to_i)
81
+ end
82
+
11
83
  # Square routing keeps the stored orthogonal trunk, even when a
12
84
  # shorter facing-edge route exists between the same boxes.
13
85
  def stored_square_route(link_row, connector, source, target)
@@ -385,7 +385,7 @@ module Ea
385
385
  geom = parse_geometry_fields(link_row.geometry)
386
386
  context = ContextDiagramSupport.package_context(diagram_row) ||
387
387
  ContextDiagramSupport.element_regenerate?(diagram_row)
388
- collapse_computed_jog(Ea::Model::DiagramConnector.new(
388
+ model = collapse_computed_jog(Ea::Model::DiagramConnector.new(
389
389
  id: IdNormalizer.synthetic("dc", diagram_row.diagram_id,
390
390
  link_row.instance_id),
391
391
  diagram_id: IdNormalizer.from_guid(diagram_row.ea_guid),
@@ -410,6 +410,7 @@ module Ea
410
410
  has_geometry_offsets: geometry_has_offsets?(link_row.geometry),
411
411
  is_substitutable: substitutable_connector?(connector)
412
412
  ), link_row, diagram_row, geom)
413
+ correct_stored_ray_origins(model, link_row, diagram_row, geom, context)
413
414
  end
414
415
 
415
416
  # Ray origin for one connector end: the element's center
@@ -106,7 +106,7 @@ module Ea
106
106
  def outline_connector?(connector, bounds)
107
107
  return true if %w[Generalization Aggregation].include?(connector.connector_type)
108
108
 
109
- return false unless stored_association?(connector)
109
+ return false unless stored_association?(connector) || offset_free_association?(connector)
110
110
 
111
111
  # Diagonal Association rounding and tree docks keep their existing rules.
112
112
  pairs = clipped_pairs(bounds, [connector.source_anchor, connector.target_anchor])
@@ -122,6 +122,20 @@ module Ea
122
122
  end
123
123
  private_class_method :stored_association?
124
124
 
125
+ def offset_free_association?(connector)
126
+ style = connector.style.to_h
127
+ connector.connector_type == "Association" && style[:mode] == "3" && !style[:tree] &&
128
+ %i[direct regenerated].none? { |key| style.key?(key) } && offset_free_anchors?(connector)
129
+ end
130
+ private_class_method :offset_free_association?
131
+
132
+ def offset_free_anchors?(connector)
133
+ !connector.has_geometry_offsets &&
134
+ [connector.source_port, connector.target_port].all?(&:nil?) &&
135
+ [connector.source_anchor, connector.target_anchor].all?
136
+ end
137
+ private_class_method :offset_free_anchors?
138
+
125
139
  def clipped_pairs(bounds, anchors)
126
140
  source, target = bounds
127
141
  source_anchor, target_anchor = anchors
@@ -91,6 +91,8 @@ module Ea
91
91
  role_seat(direction, anchor, text_box, role) || text_pos
92
92
  mult_pos = directional_multiplicity(connector, direction, anchor, mult_box, mult) ||
93
93
  mult_seat(direction, anchor, mult_box) || mult_pos
94
+ elsif end_kind == :target && !(tree && zero_offset?(text_box, mult_box))
95
+ mult_pos = target_multiplicity_seat(heading, anchor, mult_box) || mult_pos
94
96
  end
95
97
 
96
98
  build_texts(role:, mult:, standalone:,
@@ -251,6 +253,14 @@ module Ea
251
253
  [x - width - 3, y + 15] if width
252
254
  end
253
255
 
256
+ def target_multiplicity_seat(heading, anchor, box)
257
+ return nil unless seat_font?
258
+ return nil unless heading && heading[0].zero? && heading[1].negative?
259
+ return nil unless cambria_box?(box) && stored_offsets_zero?(box)
260
+
261
+ [anchor[0] + 8, anchor[1] - 7]
262
+ end
263
+
254
264
  def cambria_box?(box)
255
265
  box && default_presentation?(box) && font_family.to_s.casecmp("Cambria").zero?
256
266
  end
@@ -97,6 +97,7 @@ module Ea
97
97
  mult_box: tgt_mb,
98
98
  anchor: target_pt, connector: connector,
99
99
  end_kind: :target, tree: tree && tree[:target],
100
+ heading: stored_tgt && leg_heading(points.reverse),
100
101
  stored_labels: stored_labels).each { |t| texts << t }
101
102
  texts
102
103
  end
@@ -112,11 +113,21 @@ module Ea
112
113
  { source: true, target: true }
113
114
  end
114
115
 
115
- # Clipping can slant a stored vertical leg. Keep its label direction
116
- # while the label position follows the final emitted endpoint.
116
+ # A diagonal clipped leg keeps the seat of its unambiguous exit face.
117
+ # Unknown faces retain the stored-upward fallback.
117
118
  def source_heading(connector, points)
118
119
  heading = leg_heading(points)
119
- return heading unless points.size == 2 && heading[0].nonzero? && heading[1].negative?
120
+ return heading unless points.size == 2 && heading.none?(&:zero?)
121
+
122
+ box = source_dock_bounds(connector)
123
+ face = box && dock_face_heading(points.first, box)
124
+ return face if face && face.zip(heading).any? { |axis, delta| (axis * delta).positive? }
125
+
126
+ stored_upward_heading(connector, heading)
127
+ end
128
+
129
+ def stored_upward_heading(connector, heading)
130
+ return heading unless heading[1].negative?
120
131
 
121
132
  stored = waypoint_pairs(connector)
122
133
  return heading unless stored.size == 2
@@ -125,6 +136,49 @@ module Ea
125
136
  original[0].zero? && original[1].negative? ? original : heading
126
137
  end
127
138
 
139
+ def source_dock_bounds(connector)
140
+ return nil unless model_index && drawn_bounds
141
+
142
+ relationship = model_index[connector.relationship_ref]
143
+ return nil unless relationship
144
+
145
+ source, target = ConnectorRedock.end_refs(relationship)
146
+ return nil if source == target
147
+ return nil unless drawn_bounds[target]
148
+
149
+ drawn_bounds[source]
150
+ end
151
+
152
+ def dock_face_heading(point, box)
153
+ return nil unless box.width.positive? && box.height.positive?
154
+
155
+ vertical_dock_heading(point, box) || horizontal_dock_heading(point, box)
156
+ end
157
+
158
+ def vertical_dock_heading(point, box)
159
+ x, y = point
160
+ left = box.x
161
+ return nil unless x > left && x < left + box.width
162
+
163
+ top = box.y
164
+ return [0, -1] if [top, top - 1].include?(y)
165
+
166
+ bottom = top + box.height
167
+ [0, 1] if [bottom, bottom + 1].include?(y)
168
+ end
169
+
170
+ def horizontal_dock_heading(point, box)
171
+ x, y = point
172
+ top = box.y
173
+ return nil unless y > top && y < top + box.height
174
+
175
+ left = box.x
176
+ return [-1, 0] if [left, left - 1].include?(x)
177
+
178
+ right = left + box.width
179
+ [1, 0] if [right, right + 1].include?(x)
180
+ end
181
+
128
182
  def leg_heading(points)
129
183
  [points[1][0] - points[0][0], points[1][1] - points[0][1]]
130
184
  end
@@ -172,7 +226,7 @@ module Ea
172
226
  theme: theme,
173
227
  font_family: label_font_family,
174
228
  font_size: label_font_size,
175
- font_unit: theme.font_size_unit
229
+ font_unit: theme.label_font_size_unit
176
230
  )
177
231
  end
178
232
 
@@ -182,7 +236,7 @@ module Ea
182
236
  model_index: model_index,
183
237
  font_family: label_font_family,
184
238
  font_size: label_font_size,
185
- font_unit: theme.font_size_unit
239
+ font_unit: theme.label_font_size_unit
186
240
  )
187
241
  end
188
242
 
@@ -212,7 +266,7 @@ module Ea
212
266
  end
213
267
 
214
268
  def label_font_size
215
- theme.font_size || DEFAULT_SIZE
269
+ theme.label_font_size || DEFAULT_SIZE
216
270
  end
217
271
  end
218
272
  end
@@ -65,7 +65,8 @@ module Ea
65
65
  text_y_offset: 12, line_height: 13).freeze
66
66
 
67
67
  def initialize(id:, name: nil, font_family: nil, font_size: nil,
68
- label_font_family: nil,
68
+ label_font_family: nil, label_font_size: nil,
69
+ label_font_size_unit: nil,
69
70
  font_size_unit: "pt", text_weight_normal: 400,
70
71
  text_weight_bold: 700,
71
72
  element_font_size: 9, element_font_unit: "pt",
@@ -83,6 +84,8 @@ module Ea
83
84
  @name = name
84
85
  @font_family = font_family
85
86
  @label_font_family = label_font_family
87
+ @label_font_size = label_font_size
88
+ @label_font_size_unit = label_font_size_unit
86
89
  @font_size = font_size
87
90
  @font_size_unit = font_size_unit
88
91
  @text_weight_normal = text_weight_normal
@@ -125,8 +128,18 @@ module Ea
125
128
  @label_font_family || font_family
126
129
  end
127
130
 
131
+ def label_font_size
132
+ @label_font_size || font_size
133
+ end
134
+
135
+ def label_font_size_unit
136
+ @label_font_size_unit || font_size_unit
137
+ end
138
+
128
139
  def with(**overrides)
129
- overrides[:label_font_family] = nil if overrides.key?(:font_family) && !overrides.key?(:label_font_family)
140
+ clear_label_override(overrides, :font_family, :label_font_family)
141
+ clear_label_override(overrides, :font_size, :label_font_size)
142
+ clear_label_override(overrides, :font_size_unit, :label_font_size_unit)
130
143
  Definition.new(**to_h.merge(overrides))
131
144
  end
132
145
 
@@ -159,6 +172,8 @@ module Ea
159
172
  font_family: font_family, font_size: font_size,
160
173
  font_size_unit: font_size_unit,
161
174
  label_font_family: @label_font_family,
175
+ label_font_size: @label_font_size,
176
+ label_font_size_unit: @label_font_size_unit,
162
177
  text_weight_normal: text_weight_normal,
163
178
  text_weight_bold: text_weight_bold,
164
179
  element_font_size: element_font_size,
@@ -179,6 +194,12 @@ module Ea
179
194
  package: package, note: note, fills: fills
180
195
  }
181
196
  end
197
+
198
+ private
199
+
200
+ def clear_label_override(overrides, global_key, label_key)
201
+ overrides[label_key] = nil if overrides.key?(global_key) && !overrides.key?(label_key)
202
+ end
182
203
  end
183
204
  end
184
205
  end
@@ -10,7 +10,7 @@ module Ea
10
10
  # name: EA White Theme
11
11
  # font: { family: Carlito, size: 7, unit: pt, weight_normal: 400, ... }
12
12
  # element_font: { size: 9, unit: pt }
13
- # label_font: { family: Cambria }
13
+ # label_font: { family: Cambria, size: 7, unit: pt }
14
14
  # colors: { text: "#000000", attribute_text: "#66413F", ... }
15
15
  # strokes: { element_border: 2, connector_line: 2, ... }
16
16
  # text_metrics: { width_factor: 0.65 }
@@ -56,6 +56,8 @@ module Ea
56
56
  name: data["name"],
57
57
  font_family: font["family"],
58
58
  label_font_family: label_font["family"],
59
+ label_font_size: label_font["size"],
60
+ label_font_size_unit: label_font["unit"],
59
61
  font_size: font["size"],
60
62
  font_size_unit: font["unit"] || "pt",
61
63
  text_weight_normal: font["weight_normal"] || 400,
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.96"
7
+ VERSION = "0.6.97"
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.96
4
+ version: 0.6.97
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -501,6 +501,7 @@ files:
501
501
  - config/qea_schema.yml
502
502
  - config/stereotype_colors.yml
503
503
  - config/themes/119.yml
504
+ - config/themes/39.yml
504
505
  - config/themes/default.yml
505
506
  - docs/ea_to_uml_type_mapping.md
506
507
  - docs/xmi_qea_conversion_capabilities.md