File: box_layout.py

package info (click to toggle)
raysession 0.17.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 19,168 kB
  • sloc: python: 44,371; sh: 1,538; makefile: 208; xml: 86
file content (233 lines) | stat: -rw-r--r-- 9,093 bytes parent folder | download
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
from enum import IntEnum
from dataclasses import dataclass
import logging
from typing import TYPE_CHECKING

from patshared import PortMode, BoxLayoutMode
from .init_values import CanvasNeverInit, canvas, options
from .utils import next_width_on_grid, next_height_on_grid

if TYPE_CHECKING:
    from .box_widget import BoxWidget

_logger = logging.getLogger(__name__)


class TitleOn(IntEnum):
    TOP = 0
    SIDE = 1
    SIDE_UNDER_ICON = 2


@dataclass()
class PortsMinSizes:
    last_in_pos: float
    last_out_pos: float
    last_inout_pos: float
    ins_width: float
    outs_width: float
    n_in_type_and_subs: int
    n_out_type_and_subs: int
    n_inout_type_and_subs: int
    last_port_mode: PortMode


class BoxLayout:
    @classmethod
    def init_from_box(
            cls, box: 'BoxWidget',
            ports_min_sizes: PortsMinSizes):
        canvas.ensure_init()

        # never call for external one of theses attributes !
        # Indeed, for optimization reasons, all BoxLayout instances are modified
        # when we init one from box.
        cls._pms = ports_min_sizes
        theme = box.get_theme()
        cls._pen_width = theme.fill_pen.widthF()
        cls._port_spacing = theme.port_spacing
        cls._hwr = canvas.theme.hardware_rack_width if box.is_hardware else 0
        cls._port_mode = box._current_port_mode
        cls._can_handle_gui = box._can_handle_gui
        cls._is_hardware = box.is_hardware
    
    @classmethod
    def width_for_ports(cls):
        return (cls._pms.ins_width + cls._pms.outs_width + 6.0)
    
    def __init__(self, n_lines: int,
                 layout_mode: BoxLayoutMode,
                 title_on: TitleOn,
                 title_template: dict[str, int]):
        canvas.ensure_init()

        self.n_lines = n_lines
        self.layout_mode = layout_mode
        self.title_on = title_on
        self.one_column = False
        self.header_width = title_template['header_width']
        self.header_height = title_template['header_height']
        
        height_for_ports = max(self._pms.last_in_pos, self._pms.last_out_pos)

        if self._port_mode in (PortMode.INPUT, PortMode.OUTPUT):
            if self._port_mode is PortMode.INPUT:
                ports_width = self._pms.ins_width
            else:
                ports_width = self._pms.outs_width

            if layout_mode is BoxLayoutMode.LARGE:
                if title_on is TitleOn.SIDE:
                    self.needed_width = (
                        ports_width + self.header_width + self._pen_width)
                    self.needed_height = (
                        max(self.header_height,
                            height_for_ports + self._port_spacing)
                        + 2 * self._pen_width)

                elif title_on is TitleOn.SIDE_UNDER_ICON:
                    self.header_width = max(
                        38, title_template['title_width'] + 10)
                    self.header_height = title_template['title_height'] + 32

                    if self._can_handle_gui:
                        self.header_width += 4
                        self.header_height += 4
                        
                    self.needed_width = (ports_width + self.header_width
                                         + self._pen_width)

                    self.needed_height = (
                        max(height_for_ports + self._port_spacing,
                            self.header_height)
                        + 2 * self._pen_width)
                else:
                    _logger.error(
                        f'incompatible _BoxLayout {layout_mode}'
                        f' and TitleOn {title_on}')
            else:
                self.needed_width = (
                    max(self.header_width + 2 * self._pen_width,
                        self.width_for_ports()))
                self.needed_height = (
                    self.header_height + height_for_ports
                    + 2 * self._pen_width)
        else:
            if layout_mode is BoxLayoutMode.HIGH:
                self.one_column = True
                self.needed_width = (
                    max(self.header_width + 2 * self._pen_width,
                        30.0 + max(self._pms.ins_width, self._pms.outs_width)))
                self.needed_height = (
                    self.header_height + self._pms.last_inout_pos
                    + 2 * self._pen_width)
            else:
                self.needed_width = (
                    max(self.header_width + 2 * self._pen_width,
                        self.width_for_ports()))
                self.needed_height = (
                    self.header_height + height_for_ports
                    + 2 * self._pen_width)

        self.full_width = next_width_on_grid(self._hwr * 2 + self.needed_width)
        self.full_height = next_height_on_grid(self._hwr * 2 + self.needed_height)

        # n_cells is used to sort layouts, to use the littlest area
        self._n_cells = (
            ((self.full_width + canvas.theme.box_spacing) / options.cell_width)
            * ((self.full_height + canvas.theme.box_spacing) / options.cell_height))

        # with the option box_grouped_auto_layout_ratio,
        # we simulate that the area can be higher in one_column mode
        # (PortMode.BOTH and BoxLayoutMode.HIGH)
        if self.one_column:
            self._n_cells *= options.box_grouped_auto_layout_ratio

        self.width = self.full_width - 2 * self._hwr
        self.height = self.full_height - 2 * self._hwr

    def __lt__(self, other: 'BoxLayout') -> bool:
        if self._n_cells != other._n_cells:
            return self._n_cells < other._n_cells
        
        if self.n_lines != other.n_lines:
            return self.n_lines < other.n_lines
        
        if self.one_column is not other.one_column:
            return self.one_column < other.one_column
        
        return self.title_on < other.title_on

    def set_choosed(self):
        self._pms = PortsMinSizes(**self._pms.__dict__)
        
        if (self._port_mode in (PortMode.INPUT, PortMode.OUTPUT)
                and self.layout_mode is BoxLayoutMode.LARGE):
            needed_width = 2 * self._pen_width + self.header_width
            self.full_wrapped_width = \
                next_width_on_grid(self._hwr * 2 + needed_width)
            self.wrapped_width = self.full_wrapped_width - 2 * self._hwr

            needed_height = (2 * self._pen_width + self.header_height)
            self.full_wrapped_height = \
                next_height_on_grid(self._hwr * 2 + needed_height)
            self.wrapped_height = self.full_wrapped_height - 2 * self._hwr
        else:
            self.wrapped_width = self.width
            self.full_wrapped_width = self.full_width

            if (self.title_on is TitleOn.TOP
                    and (self.width - self.header_width) / 2 >= 14):
                needed_height = (2 * self._pen_width + self.header_height)
            else:
                needed_height = (self._pen_width
                                 + self.header_height
                                 + max(12, self._pen_width))
            
            self.full_wrapped_height = \
                next_height_on_grid(self._hwr * 2 + needed_height)
            self.wrapped_height = self.full_wrapped_height - 2 * self._hwr
        
        self.exceeding_y_ins = 0.0
        self.exceeding_y_outs = 0.0
        self.exceeding_y_inouts = 0.0
        
        if ((self._port_mode is PortMode.BOTH
                    and self.layout_mode is BoxLayoutMode.LARGE)
                or (self._port_mode in (PortMode.INPUT, PortMode.OUTPUT)
                    and self.layout_mode is BoxLayoutMode.HIGH)):
            self.exceeding_y_ins = (
                self.height 
                - (2 * self._pen_width + self.header_height
                    + self._pms.last_in_pos))
            self.exceeding_y_outs = (
                self.height 
                - (2 * self._pen_width + self.header_height
                    + self._pms.last_out_pos))

        elif self._port_mode is PortMode.OUTPUT:
            self.exceeding_y_outs = (
                self.height
                - (2 * self._pen_width + self._port_spacing
                   + self._pms.last_out_pos))
        
        elif self._port_mode is PortMode.INPUT:
            self.exceeding_y_ins = (
                self.height
                - (2 * self._pen_width + self._port_spacing
                   + self._pms.last_in_pos))
        else:
            self.exceeding_y_inouts = (
                self.height
                - (2 * self._pen_width + self.header_height
                   + self._pms.last_inout_pos))
            
    def set_ports_top_bottom(
            self, ports_top_in: float, ports_bottom_in: float,
            ports_top_out: float, ports_bottom_out: float):
        self.ports_top_in = ports_top_in
        self.ports_bottom_in = ports_bottom_in
        self.ports_top_out = ports_top_out
        self.ports_bottom_out = ports_bottom_out