1# Copyright (c) 2019-2020, Manfred Moitzi
2# License: MIT License
3from typing import TYPE_CHECKING, Iterable, Optional, Union
4from ezdxf.lldxf import const
5from .base import BaseLayout
6
7if TYPE_CHECKING:
8    from ezdxf.eztypes import DXFGraphic, AttDef
9
10
11class BlockLayout(BaseLayout):
12    """ BlockLayout has the same factory-functions as Layout, but is managed
13    in the :class:`BlocksSection` class. It represents a DXF Block.
14
15    """
16
17    def __contains__(self, entity: Union['DXFGraphic', str]) -> bool:
18        """ Returns ``True`` if block contains `entity`.
19
20        Args:
21             entity: :class:`DXFGraphic` object or handle as hex string
22
23        """
24        if isinstance(entity, str):
25            entity = self.entitydb[entity]
26        return entity in self.entity_space
27
28    @property
29    def block(self):
30        """ the associated :class:`~ezdxf.entities.Block` entity. """
31        return self.block_record.block
32
33    @property
34    def endblk(self):
35        """ the associated :class:`~ezdxf.entities.EndBlk` entity. """
36        return self.block_record.endblk
37
38    @property
39    def name(self) -> str:
40        """ Get block and block_record name """
41        return self.block_record.dxf.name
42
43    @name.setter
44    def name(self, new_name) -> None:
45        """ Set block and block_record name """
46        self.block_record.rename(new_name)
47
48    @property
49    def dxf(self):
50        """ DXF name space of associated :class:`~ezdxf.entities.BlockRecord`
51        table entry.
52        """
53        return self.block_record.dxf
54
55    @property
56    def can_explode(self) -> bool:
57        """ Set property to ``True`` to allow exploding block references of
58        this block.
59        """
60        return bool(self.block_record.dxf.explode)
61
62    @can_explode.setter
63    def can_explode(self, value: bool):
64        self.block_record.dxf.explode = int(value)
65
66    @property
67    def scale_uniformly(self) -> bool:
68        """ Set property to ``True`` to allow block references of this block
69        only scale uniformly.
70        """
71        return bool(self.block_record.dxf.scale)
72
73    @scale_uniformly.setter
74    def scale_uniformly(self, value: bool):
75        self.block_record.dxf.scale = int(value)
76
77    def attdefs(self) -> Iterable['AttDef']:
78        """ Returns iterable of all :class:`~ezdxf.entities.attrib.Attdef`
79        entities.
80        """
81        return (entity for entity in self if entity.dxftype() == 'ATTDEF')
82
83    def has_attdef(self, tag: str) -> bool:
84        """ Returns ``True`` if an :class:`~ezdxf.entities.attrib.Attdef` for
85        `tag` exist.
86        """
87        return self.get_attdef(tag) is not None
88
89    def get_attdef(self, tag: str) -> Optional['DXFGraphic']:
90        """ Returns attached :class:`~ezdxf.entities.attrib.Attdef` entity by
91        `tag` name.
92        """
93        for attdef in self.attdefs():
94            if tag == attdef.dxf.tag:
95                return attdef
96
97    def get_attdef_text(self, tag: str, default: str = None) -> str:
98        """ Returns text content for :class:`~ezdxf.entities.attrib.Attdef`
99        `tag` as string or returns `default` if no :class:`Attdef` for `tag`
100        exist.
101
102        Args:
103            tag: name of tag
104            default: default value if `tag` not exist
105
106        """
107        attdef = self.get_attdef(tag)
108        if attdef is None:
109            return default
110        return attdef.dxf.text
111
112    def get_const_attdefs(self) -> Iterable['AttDef']:
113        """ Returns iterable for all constant ATTDEF entities. (internal API)
114        """
115        return (attdef for attdef in self.attdefs() if attdef.is_const)
116
117    def has_non_const_attdef(self) -> bool:
118        """ Returns ``True`` if the block has a non constant attribute
119        definition.
120        """
121        return any(not attdef.is_const for attdef in self.attdefs())
122
123    def update_block_flags(self):
124        state = self.has_non_const_attdef()
125        self.block.set_flag_state(const.BLK_NON_CONSTANT_ATTRIBUTES, state)