File: test_225_mtext.py

package info (click to toggle)
ezdxf 1.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 104,528 kB
  • sloc: python: 182,341; makefile: 116; lisp: 20; ansic: 4
file content (366 lines) | stat: -rw-r--r-- 10,551 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# Copyright (c) 2019-2020 Manfred Moitzi
# License: MIT License
# created 2019-03-06
import math

import pytest
from ezdxf.entities.mtext import MText
from ezdxf.layouts import VirtualLayout
from ezdxf.lldxf import const
from ezdxf.lldxf.tagwriter import TagCollector, basic_tags_from_text
from ezdxf.colors import rgb2int

MTEXT = """0
MTEXT
5
0
330
0
100
AcDbEntity
8
0
100
AcDbMText
 10
0
 20
0
 30
0
40
1.0
71
1
1

73
1
"""


@pytest.fixture
def entity():
    e = MText.from_text(MTEXT)
    return e


def test_registered():
    from ezdxf.entities.factory import ENTITY_CLASSES

    assert "MTEXT" in ENTITY_CLASSES


def test_default_init():
    entity = MText()
    assert entity.dxftype() == "MTEXT"
    assert entity.dxf.handle is None
    assert entity.dxf.owner is None


def test_virtual_text_attribute():
    """The MText content is stored in multiple tags (1, 3, 3, ...) and cannot
    be supported as a simple DXF tag.
    """
    entity = MText()
    assert entity.is_supported_dxf_attrib("text") is True

    entity.dxf.text = "Hello"
    assert entity.text == "Hello"
    assert entity.dxf.text == "Hello"


def test_setup_by_virtual_text_attribute():
    entity = MText.new(dxfattribs={"text": "content"})
    assert entity.text == "content"
    assert entity.dxf.text == "content"


def test_hasattr_for_virtual_text_attribute_is_always_false():
    entity = MText()
    entity.dxf.text = "Hello"
    assert entity.dxf.hasattr("text") is False


def test_default_new():
    entity = MText.new(
        handle="ABBA",
        owner="0",
        dxfattribs={
            "color": 7,
            "insert": (1, 2, 3),
            "char_height": 1.8,
            "width": 20,
            "defined_height": 30,
            "attachment_point": 3,
            "flow_direction": 3,
            "style": "OpenSans",
            "extrusion": (4, 5, 6),
            "text_direction": (7, 8, 9),
            "rect_width": 42,
            "rect_height": 43,
            "rotation": 50,
            "line_spacing_style": 2,
            "line_spacing_factor": 1.7,
            "box_fill_scale": 1.1,
            "bg_fill": 3,
            "bg_fill_color": 14,
            "bg_fill_true_color": 111222,
            "bg_fill_color_name": "magenta",
            "bg_fill_transparency": 1,
        },
    )
    assert entity.dxf.layer == "0"
    assert entity.dxf.color == 7
    assert entity.dxf.insert == (1, 2, 3)
    assert entity.dxf.char_height == 1.8
    assert entity.dxf.width == 20
    assert entity.dxf.defined_height == 30
    assert entity.dxf.attachment_point == 3
    assert entity.dxf.flow_direction == 3
    assert entity.dxf.extrusion == (4, 5, 6)
    assert entity.dxf.text_direction == (7, 8, 9)
    assert entity.dxf.rect_width == 42
    assert entity.dxf.rect_height == 43
    assert entity.dxf.rotation == 50
    assert entity.dxf.line_spacing_style == 2
    assert entity.dxf.line_spacing_factor == 1.7
    assert entity.dxf.box_fill_scale == 1.1
    assert entity.dxf.bg_fill == 3
    assert entity.dxf.bg_fill_color == 14
    assert entity.dxf.bg_fill_true_color == 111222
    assert entity.dxf.bg_fill_color_name == "magenta"
    assert entity.dxf.bg_fill_transparency == 1


def test_load_from_text(entity):
    assert entity.dxf.layer == "0"
    assert entity.dxf.color == 256, "default color is 256 (by layer)"
    assert entity.dxf.insert == (0, 0, 0)
    assert entity.dxf.char_height == 1.0
    assert entity.dxf.attachment_point == 1
    assert entity.dxf.line_spacing_style == 1
    assert entity.text == ""


def test_write_dxf():
    entity = MText.from_text(MTEXT)
    result = TagCollector.dxftags(entity)
    expected = basic_tags_from_text(MTEXT)
    assert result == expected


def test_expected_python_backslash_decoding():
    s = (
        r"Swiss 721 (helvetica-like)\P\P\pt7.1875,8.38542;{\H0.6667x;Regular"
        r"\P\P\pl0.899488,t8.38542;Swiss Light^I\fSwis721 Lt BT|b0|i0|c0|p34"
        r";\C5;abcdefghijABCDEFGHIJ123456789!@#$%^ &*()\P\Ftxt.shx|c1;\P\C25"
        r"6;Swiss Light Italic\Ftxt.shx|c0;^I\fSwis721 Lt BT|b0|i"
    )
    assert len(s) == 253


@pytest.fixture
def layout():
    return VirtualLayout()


@pytest.mark.parametrize(
    "text",
    [
        "test\ntext",  # single new line
        "test\r\ntext",  # single new line
        "test\ntext\rtext",  # ignore a single '\r'
    ],
)
def test_required_escaping_of_line_endings_at_dxf_export(layout, text):
    txt = layout.add_mtext(text)
    collector = TagCollector(optional=True)
    txt.export_dxf(collector)
    for tag in collector.tags:
        if tag[0] == 1:
            assert tag[1].count(r"\P") == 1
            assert "\n" not in tag[1]
            assert "\r" not in tag[1]


@pytest.mark.parametrize(
    "text",
    [
        "a new mtext",
        "0123456789" * 25 + "a new mtext",
        "0123456789" * 25 + "abcdefghij" * 25,
    ],
)
def test_new_long_mtext(layout, text):
    mtext = layout.add_mtext(text)
    assert text == mtext.text
    assert text == mtext.plain_text()


def test_default_text_chunk_size_of_250_chars(layout):
    text = "0123456789" * 25 + "abcdefghij" * 25 + "a new mtext"
    mtext = layout.add_mtext(text)
    collector = TagCollector()
    mtext.export_dxf(collector)
    first, second, last = [tag for tag in collector.tags if tag[0] in (1, 3)]

    assert first.code == 3
    assert len(first.value) == 250
    assert text.startswith(first.value)

    assert second.code == 3
    assert len(second.value) == 250
    assert text[250:500] == second.value

    assert last.code == 1
    assert text.endswith(last.value)


def test_text_direction_wins_over_rotation(layout):
    mtext = layout.add_mtext("TEST")
    mtext.dxf.text_direction = (1, 1, 0)  # 45 deg
    mtext.dxf.rotation = 30
    assert mtext.get_rotation() == 45, (
        "Text direction should have higher priority than text rotation,"
        "if both are present."
    )


def test_set_rotation_replaces_text_direction(layout):
    mtext = layout.add_mtext("TEST")
    mtext.dxf.text_direction = (1, 1, 0)  # 45 deg
    mtext.set_rotation(30)
    assert mtext.get_rotation() == 30
    assert mtext.dxf.hasattr("text_direction") is False


def test_append_text(layout):
    mtext = layout.add_mtext("abc")
    mtext += "def"
    assert mtext.text == "abcdef"


def test_set_location(layout):
    mtext = layout.add_mtext("TEST")
    mtext.set_location(
        insert=(3, 4),
        rotation=15,
        attachment_point=const.MTEXT_MIDDLE_CENTER,
    )
    assert const.MTEXT_MIDDLE_CENTER == mtext.dxf.attachment_point
    assert mtext.dxf.rotation == 15
    assert (3, 4, 0) == mtext.dxf.insert


def test_set_bg_color(layout):
    mtext = layout.add_mtext("TEST").set_bg_color(2)
    assert mtext.dxf.bg_fill == 1
    assert mtext.dxf.bg_fill_color == 2
    assert (
        mtext.dxf.hasattr("box_fill_scale") is True
    ), "box_fill_scale attribute must exists, else AutoCAD complains"


def test_set_bg_true_color(layout):
    mtext = layout.add_mtext("TEST").set_bg_color((10, 20, 30), scale=2)
    assert mtext.dxf.bg_fill == 1
    assert mtext.dxf.bg_fill_true_color == rgb2int((10, 20, 30))
    assert mtext.dxf.box_fill_scale == 2
    assert (
        mtext.dxf.hasattr("bg_fill_color") is True
    ), "bg_fill_color attribute must exists, else AutoCAD complains"


def test_delete_bg_color(layout):
    mtext = layout.add_mtext("TEST").set_bg_color(None)
    # AutoCAD always complains about anything if bg_fill is set to 0,
    # so I delete all related tags.
    assert mtext.dxf.hasattr("bg_fill") is False
    assert mtext.dxf.hasattr("bg_fill_color") is False
    assert mtext.dxf.hasattr("bg_fill_true_color") is False
    assert mtext.dxf.hasattr("bg_fill_color_name") is False
    assert mtext.dxf.hasattr("box_fill_scale") is False


def test_set_bg_canvas_color(layout):
    mtext = layout.add_mtext("TEST").set_bg_color("canvas")
    assert mtext.dxf.bg_fill == 3
    assert (
        mtext.has_dxf_attrib("bg_fill_color") is True
    ), "bg_fill_color attribute must exists, else AutoCAD complains"
    assert (
        mtext.has_dxf_attrib("box_fill_scale") is True
    ), "box_fill_scale attribute must exists, else AutoCAD complains"


def test_set_text_frame_only(layout):
    # special case, text frame only with scaling factor = 1.5
    mtext = layout.add_mtext("TEST").set_bg_color(None, text_frame=True)
    assert mtext.dxf.bg_fill == const.MTEXT_TEXT_FRAME
    assert mtext.dxf.hasattr("bg_fill_color") is False
    assert mtext.dxf.hasattr("bg_fill_true_color") is False
    assert mtext.dxf.hasattr("bg_fill_color_name") is False
    assert mtext.dxf.hasattr("box_fill_scale") is False


def test_transform_interface():
    mtext = MText()
    mtext.dxf.insert = (1, 0, 0)
    mtext.translate(1, 2, 3)
    assert mtext.dxf.insert == (2, 2, 3)


def test_bg_fill_flags():
    mtext = MText.new()
    mtext.dxf.bg_fill = 0  # bg fill off
    mtext.dxf.bg_fill = 1  # bg fill as color
    assert mtext.dxf.bg_fill == 1
    mtext.dxf.bg_fill = 2  # bg fill as window color
    assert mtext.dxf.bg_fill == 2
    mtext.dxf.bg_fill = 3  # bg fill as background color
    assert mtext.dxf.bg_fill == 3
    mtext.dxf.bg_fill = 0x10  # text frame?
    assert mtext.dxf.bg_fill == 0x10
    mtext.dxf.bg_fill = 4  # invalid flag
    assert mtext.dxf.bg_fill == 0
    mtext.dxf.bg_fill = 0x20  # invalid flag
    assert mtext.dxf.bg_fill == 0


def test_get_text_direction_from_text_direction():
    mtext = MText()
    mtext.dxf.text_direction = (1, 2, 3)
    assert mtext.get_text_direction().isclose((1, 2, 3))


def test_get_text_direction_from_rotation():
    mtext = MText()
    mtext.dxf.rotation = 45
    s = math.sin(math.radians(mtext.dxf.rotation))
    assert mtext.get_text_direction().isclose((s, s, 0))


def test_convert_rotation_to_text_direction():
    mtext = MText()
    mtext.dxf.rotation = 45
    mtext.convert_rotation_to_text_direction()
    assert mtext.dxf.hasattr("rotation") is False
    assert mtext.dxf.hasattr("text_direction") is True
    old = mtext.dxf.text_direction

    # calling again, does nothing
    mtext.convert_rotation_to_text_direction()
    assert mtext.dxf.hasattr("rotation") is False
    assert mtext.dxf.hasattr("text_direction") is True
    assert old.isclose(mtext.dxf.text_direction)


def test_get_ucs():
    mtext = MText()
    mtext.dxf.insert = (1, 2, 3)
    m = mtext.ucs().matrix
    assert m.origin.isclose((1, 2, 3))
    assert m.ux.isclose((1, 0, 0))
    assert m.uy.isclose((0, 1, 0))
    assert m.uz.isclose((0, 0, 1))