ea 0.6.106 → 0.6.108
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 +4 -4
- data/config/themes/119.yml +3 -2
- data/lib/ea/fonts/cambria_7_styled_widths.json +293 -0
- data/lib/ea/fonts/metrics.rb +50 -7
- data/lib/ea/model/diagram_element.rb +4 -0
- data/lib/ea/sources/qea/diagram_builder/auto_routing.rb +124 -11
- data/lib/ea/sources/qea/diagram_builder/font_settings.rb +50 -0
- data/lib/ea/sources/qea/diagram_builder/routing.rb +82 -82
- data/lib/ea/sources/qea/diagram_builder.rb +9 -30
- data/lib/ea/sources/qea/instance_builder.rb +1 -0
- data/lib/ea/sources/qea/property_builder.rb +11 -1
- data/lib/ea/svg/ea_emitter/color_resolver.rb +1 -2
- data/lib/ea/svg/ea_emitter/compartment/attributes.rb +2 -1
- data/lib/ea/svg/ea_emitter/compartment/constraints.rb +5 -14
- data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +11 -5
- data/lib/ea/svg/ea_emitter/compartment/header.rb +2 -1
- data/lib/ea/svg/ea_emitter/compartment/note_body.rb +6 -4
- data/lib/ea/svg/ea_emitter/compartment/note_html.rb +66 -0
- data/lib/ea/svg/ea_emitter/compartment/operations.rb +2 -1
- data/lib/ea/svg/ea_emitter/compartment.rb +1 -0
- data/lib/ea/svg/ea_emitter/connector_redock.rb +30 -14
- data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +11 -9
- data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +42 -17
- data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +46 -15
- data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +34 -2
- data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +8 -5
- data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +3 -2
- data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +10 -5
- data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +2 -1
- data/lib/ea/svg/ea_emitter/element/header_renderer.rb +14 -12
- data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +10 -7
- data/lib/ea/svg/ea_emitter/elements.rb +41 -33
- data/lib/ea/svg/ea_emitter/font_resolver.rb +14 -4
- data/lib/ea/svg/ea_emitter/ghost_labels.rb +3 -0
- data/lib/ea/svg/ea_emitter/label/end_label.rb +37 -4
- data/lib/ea/svg/ea_emitter/labels.rb +12 -4
- data/lib/ea/svg/ea_emitter/marker/diamond.rb +17 -23
- data/lib/ea/svg/ea_emitter/render_context.rb +1 -1
- data/lib/ea/svg/ea_emitter/text_renderer.rb +6 -5
- data/lib/ea/theme/definition.rb +5 -2
- data/lib/ea/theme/loader.rb +3 -2
- data/lib/ea/version.rb +1 -1
- data/memory/deviations.md +3 -0
- metadata +5 -1
|
@@ -116,6 +116,7 @@ module Ea
|
|
|
116
116
|
size = font_resolver.size_for(element)
|
|
117
117
|
family = font_resolver.family_for(element)
|
|
118
118
|
size_unit = font_resolver.size_unit_for(element)
|
|
119
|
+
logical_height = font_resolver.logical_height_for(element)
|
|
119
120
|
parent_name = off_canvas_parent_name_for(classifier)
|
|
120
121
|
|
|
121
122
|
|
|
@@ -135,7 +136,8 @@ module Ea
|
|
|
135
136
|
classifier.properties.to_a.any? { |pr| !pr.association_id }))
|
|
136
137
|
Element::AttributeRenderer.lines_for(
|
|
137
138
|
classifier, lookup: attribute_lookup,
|
|
138
|
-
|
|
139
|
+
exclude_association_ids: drawn_association_ids,
|
|
140
|
+
stored_order: element.style&.fetch(:stored_attribute_order, false)
|
|
139
141
|
)
|
|
140
142
|
else
|
|
141
143
|
[]
|
|
@@ -151,8 +153,8 @@ module Ea
|
|
|
151
153
|
# 22 + 3 (CharacterString 197+27=224, Integer 92+25=117).
|
|
152
154
|
# Titles never drive growth - they wrap instead.
|
|
153
155
|
if attr_lines.any? || op_lines.any?
|
|
154
|
-
row_w = [row_content_width(attr_lines, 5, size, family),
|
|
155
|
-
row_content_width(op_lines, 3, size, family)].compact.max
|
|
156
|
+
row_w = [row_content_width(attr_lines, 5, size, family, logical_height),
|
|
157
|
+
row_content_width(op_lines, 3, size, family, logical_height)].compact.max
|
|
156
158
|
if row_w && row_w > bounds.width
|
|
157
159
|
bounds = Ea::Model::Bounds.new(
|
|
158
160
|
x: bounds.x, y: bounds.y,
|
|
@@ -166,18 +168,19 @@ module Ea
|
|
|
166
168
|
visually_nested: visually_nested?(element),
|
|
167
169
|
umldi_keyword: element.umldi_keyword,
|
|
168
170
|
bounds_width: bounds.width,
|
|
169
|
-
font_size: size,
|
|
171
|
+
font_size: size, logical_height: logical_height,
|
|
170
172
|
family: family,
|
|
171
173
|
off_canvas_parent_name: parent_name,
|
|
172
174
|
foreign_package_name: foreign_package_name_for(classifier),
|
|
173
175
|
suppress_stereotypes: suppress_stereotypes?) : []
|
|
174
176
|
geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
177
|
+
tagged_values_for(classifier).size,
|
|
178
|
+
header_lines, classifier: classifier, family: family,
|
|
179
|
+
size_unit: size_unit, logical_height: logical_height,
|
|
180
|
+
constraints_count: constraints_for(classifier).size,
|
|
181
|
+
marker_count: marker_lines_for(classifier, element).size,
|
|
182
|
+
enum_literals_count: enum_row_count_for(classifier),
|
|
183
|
+
attr_group_lead: Element::AttributeRenderer.group_lead_total(attr_lines))
|
|
181
184
|
# EA suppresses the whole attribute compartment when its
|
|
182
185
|
# rows do not fit the stored box height (never truncates
|
|
183
186
|
# rows) - the AOS box on CityFurniture hides its
|
|
@@ -195,12 +198,13 @@ module Ea
|
|
|
195
198
|
geometry.attr_bottom_y.to_i > bounds.y + bounds.height
|
|
196
199
|
attr_lines = []
|
|
197
200
|
geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
tagged_values_for(classifier).size,
|
|
202
|
+
header_lines, classifier: classifier, family: family,
|
|
203
|
+
size_unit: size_unit, logical_height: logical_height,
|
|
204
|
+
constraints_count: constraints_for(classifier).size,
|
|
205
|
+
marker_count: marker_lines_for(classifier, element).size,
|
|
206
|
+
enum_literals_count: enum_row_count_for(classifier),
|
|
207
|
+
attr_group_lead: Element::AttributeRenderer.group_lead_total(attr_lines))
|
|
204
208
|
end
|
|
205
209
|
# EA suppresses the operations compartment when its rows
|
|
206
210
|
# overflow the stored box height (same rule as attributes)
|
|
@@ -215,22 +219,24 @@ module Ea
|
|
|
215
219
|
height: geometry.op_bottom_y.to_i + 8 - bounds.y
|
|
216
220
|
)
|
|
217
221
|
geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
222
|
+
tagged_values_for(classifier).size,
|
|
223
|
+
header_lines, classifier: classifier, family: family,
|
|
224
|
+
size_unit: size_unit, logical_height: logical_height,
|
|
225
|
+
constraints_count: constraints_for(classifier).size,
|
|
226
|
+
marker_count: marker_lines_for(classifier, element).size,
|
|
227
|
+
enum_literals_count: enum_row_count_for(classifier),
|
|
228
|
+
attr_group_lead: Element::AttributeRenderer.group_lead_total(attr_lines))
|
|
224
229
|
elsif op_lines.any? && geometry.op_first_y &&
|
|
225
230
|
geometry.op_bottom_y.to_i > bounds.y + bounds.height
|
|
226
231
|
op_lines = []
|
|
227
232
|
geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
233
|
+
tagged_values_for(classifier).size,
|
|
234
|
+
header_lines, classifier: classifier, family: family,
|
|
235
|
+
size_unit: size_unit, logical_height: logical_height,
|
|
236
|
+
constraints_count: constraints_for(classifier).size,
|
|
237
|
+
marker_count: marker_lines_for(classifier, element).size,
|
|
238
|
+
enum_literals_count: enum_row_count_for(classifier),
|
|
239
|
+
attr_group_lead: Element::AttributeRenderer.group_lead_total(attr_lines))
|
|
234
240
|
end
|
|
235
241
|
# Real attributes grow the DRAWN box past the stored
|
|
236
242
|
# height instead of being dropped (0CABA7D7: stored h44
|
|
@@ -264,7 +270,7 @@ module Ea
|
|
|
264
270
|
stroke: resolve_stroke,
|
|
265
271
|
stroke_width: resolve_stroke_width,
|
|
266
272
|
text_fill: theme.text_color,
|
|
267
|
-
family: family, size: size, size_unit: size_unit,
|
|
273
|
+
family: family, size: size, size_unit: size_unit, logical_height: logical_height,
|
|
268
274
|
header_lines: header_lines,
|
|
269
275
|
attr_lines: attr_lines,
|
|
270
276
|
op_lines: op_lines,
|
|
@@ -282,14 +288,14 @@ module Ea
|
|
|
282
288
|
)
|
|
283
289
|
end
|
|
284
290
|
|
|
285
|
-
def row_content_width(lines, right_pad, size, family)
|
|
291
|
+
def row_content_width(lines, right_pad, size, family, logical_height)
|
|
286
292
|
return nil if lines.to_a.empty?
|
|
287
293
|
|
|
288
294
|
tl = lines.filter_map do |line|
|
|
289
295
|
text = line.sub(/\A\S /, "")
|
|
290
296
|
Ea::Fonts::Metrics.text_length(text, size,
|
|
291
297
|
family: family,
|
|
292
|
-
weight: "400")&.round
|
|
298
|
+
weight: "400", logical_height: logical_height)&.round
|
|
293
299
|
end.max
|
|
294
300
|
return nil unless tl
|
|
295
301
|
|
|
@@ -300,8 +306,9 @@ module Ea
|
|
|
300
306
|
tagged_count, header_lines, classifier: nil,
|
|
301
307
|
constraints_count: 0, marker_count: 0,
|
|
302
308
|
enum_literals_count: 0,
|
|
303
|
-
attr_group_lead: 0)
|
|
304
|
-
CompartmentGeometry.new(bounds: bounds, size: size,
|
|
309
|
+
attr_group_lead: 0, family: nil, size_unit: "pt", logical_height: nil)
|
|
310
|
+
CompartmentGeometry.new(bounds: bounds, size: size, family: family,
|
|
311
|
+
size_unit: size_unit, logical_height: logical_height,
|
|
305
312
|
header_ghost: header_lines.any? &&
|
|
306
313
|
%i[italic italic_tight].include?(header_lines.first.last),
|
|
307
314
|
header_ghost_tight: header_lines.any? &&
|
|
@@ -495,6 +502,7 @@ module Ea
|
|
|
495
502
|
|
|
496
503
|
def foreign_package_name_for(classifier)
|
|
497
504
|
return nil unless diagram.show_foreign
|
|
505
|
+
return nil if diagram.style_ex.to_s.split(";").include?("NoFullScope=1")
|
|
498
506
|
return nil unless classifier.is_a?(Ea::Model::Classifier)
|
|
499
507
|
|
|
500
508
|
# Nested classifiers (t_object.ParentID -> a Class) qualify
|
|
@@ -41,9 +41,8 @@ module Ea
|
|
|
41
41
|
DEFAULT_MARKER_FAMILIES.include?(explicit)
|
|
42
42
|
return explicit
|
|
43
43
|
end
|
|
44
|
-
return theme.font_family if theme.themed? && theme.font_family
|
|
45
44
|
|
|
46
|
-
diagram_default_family || DEFAULT_FONT_FAMILY
|
|
45
|
+
theme_family_for(explicit) || diagram_default_family || DEFAULT_FONT_FAMILY
|
|
47
46
|
end
|
|
48
47
|
|
|
49
48
|
def size_for(element)
|
|
@@ -58,8 +57,12 @@ module Ea
|
|
|
58
57
|
DEFAULT_ELEMENT_FONT_SIZE
|
|
59
58
|
end
|
|
60
59
|
|
|
61
|
-
def size_unit_for(
|
|
62
|
-
theme.font_size_unit || "pt"
|
|
60
|
+
def size_unit_for(element)
|
|
61
|
+
element&.font_size_unit || theme.font_size_unit || "pt"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def logical_height_for(element)
|
|
65
|
+
element&.font_logical_height if size_unit_for(element) == "pt"
|
|
63
66
|
end
|
|
64
67
|
|
|
65
68
|
def weight_for(element)
|
|
@@ -73,6 +76,13 @@ module Ea
|
|
|
73
76
|
|
|
74
77
|
private
|
|
75
78
|
|
|
79
|
+
def theme_family_for(explicit)
|
|
80
|
+
return unless theme.themed?
|
|
81
|
+
return theme.font_family if DEFAULT_MARKER_FAMILIES.include?(explicit)
|
|
82
|
+
|
|
83
|
+
theme.element_font_family || theme.font_family
|
|
84
|
+
end
|
|
85
|
+
|
|
76
86
|
# EA's app-default font depends on the system locale:
|
|
77
87
|
# Japanese Windows → "Yu Gothic UI" 13, English Windows →
|
|
78
88
|
# "Calibri" 10. We can't query EA's runtime, so we infer
|
|
@@ -42,8 +42,11 @@ module Ea
|
|
|
42
42
|
|
|
43
43
|
private
|
|
44
44
|
|
|
45
|
+
# EA does not draw a connector whose other end is missing from
|
|
46
|
+
# the diagram, so it has no waypoints and no ghost label either.
|
|
45
47
|
def visible_connectors
|
|
46
48
|
(diagram.connectors || []).select(&:renderable?)
|
|
49
|
+
.reject { |connector| connector.waypoints.empty? }
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
def text_for(ghost)
|
|
@@ -78,6 +78,7 @@ module Ea
|
|
|
78
78
|
if tree && zero_offset?(text_box, mult_box)
|
|
79
79
|
text_pos, mult_pos = tree_positions(end_kind, anchor, role,
|
|
80
80
|
text_pos, mult_pos)
|
|
81
|
+
mult_pos = tree_left_multiplicity(end_kind, heading, anchor, mult_box, mult) || mult_pos
|
|
81
82
|
elsif mult_box && stored_offsets_zero?(mult_box)
|
|
82
83
|
# Start at the legacy default; measured directional seats
|
|
83
84
|
# below replace it for default Cambria labels.
|
|
@@ -94,12 +95,14 @@ module Ea
|
|
|
94
95
|
source_property_seat(connector, direction, anchor, text_box, role) ||
|
|
95
96
|
plain_upward_seat(connector, direction, anchor, text_box, role) ||
|
|
96
97
|
role_seat(direction, anchor, text_box, role) || text_pos
|
|
97
|
-
mult_pos = directional_multiplicity(
|
|
98
|
+
mult_pos = directional_multiplicity(direction, anchor, mult_box, mult) ||
|
|
99
|
+
horizontal_tree_multiplicity(connector, direction, anchor, mult_box, mult) ||
|
|
98
100
|
mult_seat(direction, anchor, mult_box) || mult_pos
|
|
99
101
|
elsif end_kind == :target && !(tree && zero_offset?(text_box, mult_box))
|
|
100
102
|
text_pos = target_vertical_role(connector, heading, anchor, text_box, role) ||
|
|
101
103
|
target_rightward_role(heading, anchor, text_box, role) || text_pos
|
|
102
|
-
mult_pos = target_multiplicity_seat(heading, anchor, mult_box) ||
|
|
104
|
+
mult_pos = target_multiplicity_seat(heading, anchor, mult_box) ||
|
|
105
|
+
target_horizontal_multiplicity(heading, anchor, mult_box, mult) || mult_pos
|
|
103
106
|
end
|
|
104
107
|
|
|
105
108
|
build_texts(role:, mult:, standalone:,
|
|
@@ -306,17 +309,47 @@ module Ea
|
|
|
306
309
|
%w[1 3].include?(style[:mode]) && style[:lwidth] == "2" && !style[:tree]
|
|
307
310
|
end
|
|
308
311
|
|
|
309
|
-
def directional_multiplicity(
|
|
312
|
+
def directional_multiplicity(direction, anchor, box, mult)
|
|
310
313
|
return nil unless cambria_box?(box)
|
|
311
314
|
|
|
312
315
|
x, y = seat_corner(anchor, box)
|
|
313
316
|
return [x + 8, y + 15] if direction == :down
|
|
314
|
-
return nil unless direction == :left
|
|
317
|
+
return nil unless direction == :left
|
|
315
318
|
|
|
316
319
|
width = Ea::Fonts::Metrics.text_length(mult, font_size, family: font_family)
|
|
317
320
|
[x - width - 3, y + 15] if width
|
|
318
321
|
end
|
|
319
322
|
|
|
323
|
+
# On an "H" tree route a property end leaving right seats its
|
|
324
|
+
# multiplicity one text width further right than the plain
|
|
325
|
+
# rightward seat.
|
|
326
|
+
def horizontal_tree_multiplicity(connector, direction, anchor, box, mult)
|
|
327
|
+
return nil unless direction == :right && property_label?(connector, :source)
|
|
328
|
+
return nil unless connector.style.to_h[:tree] == "H" && cambria_box?(box) && !mult_empty?(mult)
|
|
329
|
+
|
|
330
|
+
width = Ea::Fonts::Metrics.text_length(mult, font_size, family: font_family)
|
|
331
|
+
x, y = seat_corner(anchor, box)
|
|
332
|
+
[x + SEAT_X_INSET + width, y + 15] if width
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
# A tree-route source leaving left seats its multiplicity like any
|
|
336
|
+
# other leftward source rather than at the rightward tree default.
|
|
337
|
+
def tree_left_multiplicity(end_kind, heading, anchor, box, mult)
|
|
338
|
+
return nil if end_kind != :source || mult_empty?(mult) || leg_direction(end_kind, heading) != :left
|
|
339
|
+
|
|
340
|
+
directional_multiplicity(:left, anchor, box, mult)
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# A target whose first leg runs sideways seats its multiplicity at
|
|
344
|
+
# the stored corner like a source leaving the same way.
|
|
345
|
+
def target_horizontal_multiplicity(heading, anchor, box, mult)
|
|
346
|
+
return nil unless seat_font? && heading && heading[1].zero? && !heading[0].zero?
|
|
347
|
+
return nil if mult_empty?(mult)
|
|
348
|
+
return directional_multiplicity(:left, anchor, box, mult) if heading[0].negative?
|
|
349
|
+
|
|
350
|
+
mult_seat(:right, anchor, box)
|
|
351
|
+
end
|
|
352
|
+
|
|
320
353
|
def target_multiplicity_seat(heading, anchor, box)
|
|
321
354
|
return nil unless seat_font?
|
|
322
355
|
return nil unless heading && heading[0].zero? && heading[1].negative?
|
|
@@ -84,24 +84,32 @@ module Ea
|
|
|
84
84
|
stored_src = end_boxes(boxes, :llt, :llb)
|
|
85
85
|
stored_tgt = end_boxes(boxes, :lrt, :lrb)
|
|
86
86
|
stored_labels = !(stored_src.nil? && stored_tgt.nil?)
|
|
87
|
-
src_tb, src_mb = stored_src ||
|
|
88
|
-
tgt_tb, tgt_mb = stored_tgt ||
|
|
87
|
+
src_tb, src_mb = stored_src || unstored_label_boxes(points, :source, stored_labels)
|
|
88
|
+
tgt_tb, tgt_mb = stored_tgt || unstored_label_boxes(points, :target, stored_labels)
|
|
89
89
|
|
|
90
90
|
texts = []
|
|
91
91
|
end_renderer.texts(text_box: src_tb, mult_box: src_mb,
|
|
92
92
|
anchor: source_pt, connector: connector,
|
|
93
93
|
end_kind: :source, tree: tree && tree[:source],
|
|
94
|
-
heading: stored_src && source_heading(connector, points),
|
|
94
|
+
heading: (stored_src || stored_labels) && source_heading(connector, points),
|
|
95
95
|
stored_labels: stored_labels).each { |t| texts << t }
|
|
96
96
|
end_renderer.texts(text_box: tgt_tb,
|
|
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 && target_heading(connector, points),
|
|
100
|
+
heading: (stored_tgt || stored_labels) && target_heading(connector, points),
|
|
101
101
|
stored_labels: stored_labels).each { |t| texts << t }
|
|
102
102
|
texts
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
+
# A connector that stores label boxes for only one end seats the
|
|
106
|
+
# other end's labels at its anchor, like a stored zero offset.
|
|
107
|
+
def unstored_label_boxes(points, end_kind, stored_labels)
|
|
108
|
+
return default_label_boxes(points, end_kind) unless stored_labels
|
|
109
|
+
|
|
110
|
+
[{ "ox" => 0, "oy" => 0, "alignment" => 0 }, { "ox" => 0, "oy" => 0, "alignment" => 0 }]
|
|
111
|
+
end
|
|
112
|
+
|
|
105
113
|
# EA tree routes are a perfect L: source-exit horizontal into
|
|
106
114
|
# the corner, vertical trunk into the target dock. Returns
|
|
107
115
|
# per-end flags when the connector matches, else nil.
|
|
@@ -4,27 +4,11 @@ module Ea
|
|
|
4
4
|
module Svg
|
|
5
5
|
module EaEmitter
|
|
6
6
|
module Marker
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# WHOLE-END SELECTION: EA flags the whole end either through
|
|
11
|
-
# t_connector.DestAccess (1 shared / 2 composite -> whole at
|
|
12
|
-
# the TARGET; corpus-verified 333EFCCF: PersonalRight_E is
|
|
13
|
-
# the DestAccess=2 end and every diamond sits there) or
|
|
14
|
-
# through the Connector_Type itself ("Aggregation"/
|
|
15
|
-
# "Composition" -> whole at the SOURCE; basic.qea's
|
|
16
|
-
# composition diagram). DestAccess wins when both appear.
|
|
17
|
-
# Without relationship data the direction heuristic applies
|
|
18
|
-
# ("Destination -> Source" -> whole at target).
|
|
19
|
-
#
|
|
20
|
-
# ARROW: dest-flagged aggregations draw a base-12 height-15
|
|
21
|
-
# open arrow stacked on the diamond tip pointing into the
|
|
22
|
-
# whole (333EFCCF: 6 diamonds + 6 path arrows). Type-inferred
|
|
23
|
-
# source-side aggregations draw the diamond only (basic.qea:
|
|
24
|
-
# 17 diamonds, 0 arrows).
|
|
7
|
+
# EA endpoint fields select the diamond end; direction selects
|
|
8
|
+
# the arrow end for target-owned aggregations.
|
|
25
9
|
class Diamond < Kind
|
|
26
10
|
def self.handles?(effective_type)
|
|
27
|
-
|
|
11
|
+
%w[Aggregation Composition].include?(effective_type)
|
|
28
12
|
end
|
|
29
13
|
|
|
30
14
|
def self.specs_for(connector, source, target, before_target, after_source, relationship: nil)
|
|
@@ -36,10 +20,8 @@ module Ea
|
|
|
36
20
|
base: whole_base)]
|
|
37
21
|
return specs unless whole_at_target
|
|
38
22
|
|
|
39
|
-
specs
|
|
40
|
-
|
|
41
|
-
base: whole_base)
|
|
42
|
-
specs
|
|
23
|
+
specs.concat(direction_specs(connector, source, target,
|
|
24
|
+
before_target, after_source))
|
|
43
25
|
end
|
|
44
26
|
|
|
45
27
|
def self.whole_at_target?(connector, relationship)
|
|
@@ -58,6 +40,18 @@ module Ea
|
|
|
58
40
|
relationship &&
|
|
59
41
|
%w[shared composite].include?(relationship.source_aggregation.to_s)
|
|
60
42
|
end
|
|
43
|
+
|
|
44
|
+
def self.direction_specs(connector, source, target, before_target,
|
|
45
|
+
after_source)
|
|
46
|
+
if connector.direction == "Destination -> Source"
|
|
47
|
+
return [Registry::Spec.new(shape: :arrow, anchor: source,
|
|
48
|
+
base: after_source)]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
[Registry::Spec.new(shape: :arrow, anchor: target,
|
|
52
|
+
base: before_target)]
|
|
53
|
+
end
|
|
54
|
+
private_class_method :direction_specs
|
|
61
55
|
end
|
|
62
56
|
end
|
|
63
57
|
end
|
|
@@ -14,7 +14,7 @@ module Ea
|
|
|
14
14
|
class RenderContext < Struct.new(
|
|
15
15
|
:element, :bounds, :model_element, :classifier,
|
|
16
16
|
:fill, :stroke, :stroke_width, :text_fill,
|
|
17
|
-
:family, :size, :size_unit,
|
|
17
|
+
:family, :size, :size_unit, :logical_height,
|
|
18
18
|
:header_lines, :attr_lines, :op_lines,
|
|
19
19
|
:enum_literals, :tagged_values, :constraints, :marker_lines,
|
|
20
20
|
:package_content_lines,
|
|
@@ -24,12 +24,12 @@ module Ea
|
|
|
24
24
|
|
|
25
25
|
attr_reader :content, :x, :y, :family, :size, :weight, :style,
|
|
26
26
|
:fill, :text_length, :rotation, :size_unit,
|
|
27
|
-
:stroke_in_text, :width_factor
|
|
27
|
+
:stroke_in_text, :width_factor, :logical_height
|
|
28
28
|
|
|
29
29
|
def initialize(content:, x:, y:, family:, size:, weight: 400,
|
|
30
30
|
style: "normal", fill: DEFAULT_FILL,
|
|
31
31
|
text_length: nil, rotation: DEFAULT_ROTATION,
|
|
32
|
-
size_unit: "px",
|
|
32
|
+
size_unit: "px", logical_height: nil,
|
|
33
33
|
stroke_in_text: DEFAULT_STROKE_IN_TEXT,
|
|
34
34
|
width_factor: DEFAULT_WIDTH_FACTOR)
|
|
35
35
|
@content = content.to_s
|
|
@@ -43,6 +43,7 @@ module Ea
|
|
|
43
43
|
@text_length = text_length
|
|
44
44
|
@rotation = rotation
|
|
45
45
|
@size_unit = size_unit
|
|
46
|
+
@logical_height = logical_height if size_unit == "pt"
|
|
46
47
|
@stroke_in_text = stroke_in_text
|
|
47
48
|
@width_factor = width_factor
|
|
48
49
|
end
|
|
@@ -154,10 +155,10 @@ module Ea
|
|
|
154
155
|
GLYPH_FALLBACK = 0.61
|
|
155
156
|
|
|
156
157
|
def self.estimate_width(text, size, _width_factor = nil, family: nil,
|
|
157
|
-
weight: nil, style: nil)
|
|
158
|
+
weight: nil, style: nil, logical_height: nil)
|
|
158
159
|
real = Ea::Fonts::Metrics.text_length(text, size, family: family,
|
|
159
160
|
weight: weight,
|
|
160
|
-
style: style)
|
|
161
|
+
style: style, logical_height: logical_height)
|
|
161
162
|
return real if real
|
|
162
163
|
|
|
163
164
|
text.to_s.each_char.sum do |ch|
|
|
@@ -170,7 +171,7 @@ module Ea
|
|
|
170
171
|
|
|
171
172
|
width = self.class.estimate_width(content, size, width_factor,
|
|
172
173
|
family: family, weight: weight,
|
|
173
|
-
style: style)
|
|
174
|
+
style: style, logical_height: logical_height)
|
|
174
175
|
width.round.to_s
|
|
175
176
|
end
|
|
176
177
|
|
data/lib/ea/theme/definition.rb
CHANGED
|
@@ -29,7 +29,7 @@ module Ea
|
|
|
29
29
|
attr_reader :id, :name,
|
|
30
30
|
:font_family, :font_size, :font_size_unit,
|
|
31
31
|
:text_weight_normal, :text_weight_bold,
|
|
32
|
-
:element_font_size, :element_font_unit,
|
|
32
|
+
:element_font_family, :element_font_size, :element_font_unit,
|
|
33
33
|
:text_color, :attribute_text_color, :method_text_color,
|
|
34
34
|
:border_color, :fill_color, :background_color,
|
|
35
35
|
:stroke_in_text_color,
|
|
@@ -69,7 +69,7 @@ module Ea
|
|
|
69
69
|
label_font_size_unit: nil,
|
|
70
70
|
font_size_unit: "pt", text_weight_normal: 400,
|
|
71
71
|
text_weight_bold: 700,
|
|
72
|
-
element_font_size: 9, element_font_unit: "pt",
|
|
72
|
+
element_font_family: nil, element_font_size: 9, element_font_unit: "pt",
|
|
73
73
|
text_color: "#000000", attribute_text_color: nil,
|
|
74
74
|
method_text_color: nil, border_color: "#000000",
|
|
75
75
|
fill_color: "#FFFFFF", background_color: "#FFFFFF",
|
|
@@ -90,6 +90,7 @@ module Ea
|
|
|
90
90
|
@font_size_unit = font_size_unit
|
|
91
91
|
@text_weight_normal = text_weight_normal
|
|
92
92
|
@text_weight_bold = text_weight_bold
|
|
93
|
+
@element_font_family = element_font_family
|
|
93
94
|
@element_font_size = element_font_size
|
|
94
95
|
@element_font_unit = element_font_unit
|
|
95
96
|
@text_color = text_color
|
|
@@ -138,6 +139,7 @@ module Ea
|
|
|
138
139
|
|
|
139
140
|
def with(**overrides)
|
|
140
141
|
clear_label_override(overrides, :font_family, :label_font_family)
|
|
142
|
+
clear_label_override(overrides, :font_family, :element_font_family)
|
|
141
143
|
clear_label_override(overrides, :font_size, :label_font_size)
|
|
142
144
|
clear_label_override(overrides, :font_size_unit, :label_font_size_unit)
|
|
143
145
|
Definition.new(**to_h.merge(overrides))
|
|
@@ -176,6 +178,7 @@ module Ea
|
|
|
176
178
|
label_font_size_unit: @label_font_size_unit,
|
|
177
179
|
text_weight_normal: text_weight_normal,
|
|
178
180
|
text_weight_bold: text_weight_bold,
|
|
181
|
+
element_font_family: element_font_family,
|
|
179
182
|
element_font_size: element_font_size,
|
|
180
183
|
element_font_unit: element_font_unit,
|
|
181
184
|
text_color: text_color,
|
data/lib/ea/theme/loader.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Ea
|
|
|
11
11
|
# font: { family: Carlito, size: 7, unit: pt, weight_normal: 400, ... }
|
|
12
12
|
# element_font: { size: 9, unit: pt }
|
|
13
13
|
# label_font: { family: Cambria, size: 7, unit: pt }
|
|
14
|
-
# colors: { text: "#000000", attribute_text: "#
|
|
14
|
+
# colors: { text: "#000000", attribute_text: "#336699", ... }
|
|
15
15
|
# strokes: { element_border: 2, connector_line: 2, ... }
|
|
16
16
|
# text_metrics: { width_factor: 0.65 }
|
|
17
17
|
# canvas: { inset_left: 35, inset_right: 50, ... }
|
|
@@ -62,10 +62,11 @@ module Ea
|
|
|
62
62
|
font_size_unit: font["unit"] || "pt",
|
|
63
63
|
text_weight_normal: font["weight_normal"] || 400,
|
|
64
64
|
text_weight_bold: font["weight_bold"] || 700,
|
|
65
|
+
element_font_family: elem_font["family"],
|
|
65
66
|
element_font_size: elem_font["size"] || 9,
|
|
66
67
|
element_font_unit: elem_font["unit"] || "pt",
|
|
67
68
|
text_color: colors["text"] || "#000000",
|
|
68
|
-
attribute_text_color: colors["attribute_text"],
|
|
69
|
+
attribute_text_color: colors["attribute_text"] || colors["text"] || "#000000",
|
|
69
70
|
method_text_color: colors["method_text"],
|
|
70
71
|
border_color: colors["border"] || "#000000",
|
|
71
72
|
fill_color: colors["fill"] || "#FFFFFF",
|
data/lib/ea/version.rb
CHANGED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
# Focused Ruby deviations
|
|
2
|
+
|
|
3
|
+
- Issue 135 attribute ordering: RuboCop Metrics/MethodLength flags the 14-line real-QEA fixture builder, and Metrics/BlockLength flags its six-example public pipeline regression group. Keep the fixture together and the directly related controls in one group; splitting them would obscure the input collections and ordering contract.
|
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.
|
|
4
|
+
version: 0.6.108
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -617,6 +617,7 @@ files:
|
|
|
617
617
|
- lib/ea/export/xsd/namespace_registry.rb
|
|
618
618
|
- lib/ea/fonts.rb
|
|
619
619
|
- lib/ea/fonts/cambria_7_regular_widths.json
|
|
620
|
+
- lib/ea/fonts/cambria_7_styled_widths.json
|
|
620
621
|
- lib/ea/fonts/carlito_metrics.json
|
|
621
622
|
- lib/ea/fonts/metrics.rb
|
|
622
623
|
- lib/ea/guid_format.rb
|
|
@@ -818,6 +819,7 @@ files:
|
|
|
818
819
|
- lib/ea/sources/qea/context_diagram_support.rb
|
|
819
820
|
- lib/ea/sources/qea/diagram_builder.rb
|
|
820
821
|
- lib/ea/sources/qea/diagram_builder/auto_routing.rb
|
|
822
|
+
- lib/ea/sources/qea/diagram_builder/font_settings.rb
|
|
821
823
|
- lib/ea/sources/qea/diagram_builder/routing.rb
|
|
822
824
|
- lib/ea/sources/qea/diagram_builder/stored_square_ports.rb
|
|
823
825
|
- lib/ea/sources/qea/diagram_style_parser.rb
|
|
@@ -892,6 +894,7 @@ files:
|
|
|
892
894
|
- lib/ea/svg/ea_emitter/compartment/instance_underline.rb
|
|
893
895
|
- lib/ea/svg/ea_emitter/compartment/marker.rb
|
|
894
896
|
- lib/ea/svg/ea_emitter/compartment/note_body.rb
|
|
897
|
+
- lib/ea/svg/ea_emitter/compartment/note_html.rb
|
|
895
898
|
- lib/ea/svg/ea_emitter/compartment/note_text.rb
|
|
896
899
|
- lib/ea/svg/ea_emitter/compartment/operations.rb
|
|
897
900
|
- lib/ea/svg/ea_emitter/compartment/package_contents.rb
|
|
@@ -1012,6 +1015,7 @@ files:
|
|
|
1012
1015
|
- lib/ea/xml_escape.rb
|
|
1013
1016
|
- lib/tasks/fonts.rake
|
|
1014
1017
|
- lib/tasks/svg_bench.rake
|
|
1018
|
+
- memory/deviations.md
|
|
1015
1019
|
- reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png
|
|
1016
1020
|
- reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png
|
|
1017
1021
|
- reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png
|