1 | |
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | import * as go from '../release/go-module.js';
|
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 | export class PanelLayoutFlow extends go.PanelLayout {
|
53 | private _direction: number = 0;
|
54 | private _spacing: go.Size = new go.Size(0, 0);
|
55 | private _lineBreadths: Array<number> = [];
|
56 | private _lineLengths: Array<number> = [];
|
57 |
|
58 | |
59 |
|
60 |
|
61 |
|
62 | constructor() {
|
63 | super();
|
64 | this.name = "Flow";
|
65 | }
|
66 |
|
67 | |
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 | get direction() { return this._direction; }
|
78 | set direction(d: number) {
|
79 | if (d !== 0 && d !== 90 && d !== 180 && d !== 270) throw new Error("bad direction for PanelLayoutFlow: " + d);
|
80 | this._direction = d;
|
81 | }
|
82 |
|
83 | |
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 | get spacing() { return this._spacing; }
|
92 | set spacing(s: go.Size) { this._spacing = s; }
|
93 |
|
94 | public measure(panel: go.Panel, width: number, height: number, elements: Array<go.GraphObject>, union: go.Rect, minw: number, minh: number): void {
|
95 | this._lineBreadths = [];
|
96 | this._lineLengths = [];
|
97 | const pad = <go.Margin>panel.padding;
|
98 | const wrapx = width + pad.left;
|
99 | const wrapy = height + pad.top;
|
100 | let x = pad.left;
|
101 | let y = pad.top;
|
102 | const xstart = x;
|
103 | const ystart = y;
|
104 |
|
105 | if (this.direction === 0 || this.direction === 180) {
|
106 | let maxx = x;
|
107 | let rowh = 0;
|
108 | for (let i = 0; i < elements.length; i++) {
|
109 | const elem = elements[i];
|
110 | if (!elem.visible) continue;
|
111 | this.measureElement(elem, Infinity, height, minw, minh);
|
112 | const mb = elem.measuredBounds;
|
113 | const marg = <go.Margin>elem.margin;
|
114 | const gw = marg.left + mb.width + marg.right;
|
115 | const gh = marg.top + mb.height + marg.bottom;
|
116 | if (x + gw > wrapx && i > 0) {
|
117 | this._lineBreadths.push(rowh);
|
118 | this._lineLengths.push(x - pad.left);
|
119 | y += rowh + this.spacing.height;
|
120 | if (y + gh <= wrapy) {
|
121 | x = xstart + gw + this.spacing.width;
|
122 | rowh = gh;
|
123 | } else {
|
124 | x = xstart;
|
125 | rowh = 0;
|
126 | break;
|
127 | }
|
128 | } else {
|
129 | x += gw + this.spacing.width;
|
130 | rowh = Math.max(rowh, gh);
|
131 | }
|
132 | maxx = Math.max(maxx, x);
|
133 | }
|
134 | this._lineBreadths.push(rowh);
|
135 | this._lineLengths.push(x - pad.left);
|
136 | union.width = Math.max(0, Math.min(maxx, wrapx) - pad.left);
|
137 | union.height = Math.max(0, y + rowh - pad.top);
|
138 | } else if (this.direction === 90 || this.direction === 270) {
|
139 | let maxy = y;
|
140 | let colw = 0;
|
141 | for (let i = 0; i < elements.length; i++) {
|
142 | const elem = elements[i];
|
143 | if (!elem.visible) continue;
|
144 | this.measureElement(elem, width, Infinity, minw, minh);
|
145 | const mb = elem.measuredBounds;
|
146 | const marg = <go.Margin>elem.margin;
|
147 | const gw = marg.left + mb.width + marg.right;
|
148 | const gh = marg.top + mb.height + marg.bottom;
|
149 | if (y + gh > wrapy && i > 0) {
|
150 | this._lineBreadths.push(colw);
|
151 | this._lineLengths.push(y - pad.top);
|
152 | x += colw + this.spacing.width;
|
153 | if (x + gw <= wrapx) {
|
154 | y = ystart + gh + this.spacing.height;
|
155 | colw = gw;
|
156 | } else {
|
157 | y = ystart;
|
158 | colw = 0;
|
159 | break;
|
160 | }
|
161 | } else {
|
162 | y += gh + this.spacing.height;
|
163 | colw = Math.max(colw, gw);
|
164 | }
|
165 | maxy = Math.max(maxy, y);
|
166 | }
|
167 | this._lineBreadths.push(colw);
|
168 | this._lineLengths.push(y - pad.top);
|
169 | union.width = Math.max(0, x + colw - pad.left);
|
170 | union.height = Math.max(0, Math.min(maxy, wrapy) - pad.top);
|
171 | }
|
172 | }
|
173 |
|
174 | private isStretched(horiz: boolean, elt: go.GraphObject, panel: go.Panel): boolean {
|
175 | let s = elt.stretch;
|
176 | if (s === go.GraphObject.Default) s = panel.defaultStretch;
|
177 | if (s === go.GraphObject.Fill) return true;
|
178 | return s === (horiz ? go.GraphObject.Vertical : go.GraphObject.Horizontal);
|
179 | }
|
180 |
|
181 | private align(elt: go.GraphObject, panel: go.Panel): go.Spot {
|
182 | let a = elt.alignment;
|
183 | if (a.isDefault()) a = panel.defaultAlignment;
|
184 | if (!a.isSpot()) a = go.Spot.Center;
|
185 | return a;
|
186 | }
|
187 |
|
188 | public arrange(panel: go.Panel, elements: Array<go.GraphObject>, union: go.Rect): void {
|
189 | const pad = <go.Margin>panel.padding;
|
190 | let x = (this.direction === 180) ? union.width - pad.right : pad.left;
|
191 | let y = (this.direction === 270) ? union.height - pad.bottom : pad.top;
|
192 | const xstart = x;
|
193 | const ystart = y;
|
194 | if (this.direction === 0) {
|
195 | let row = 0;
|
196 | for (let i = 0; i < elements.length; i++) {
|
197 | const elem = elements[i];
|
198 | if (!elem.visible) continue;
|
199 | const mb = elem.measuredBounds;
|
200 | const marg = <go.Margin>elem.margin;
|
201 | const gw = marg.left + mb.width + marg.right;
|
202 |
|
203 | if (x - pad.left > this._lineLengths[row] - 0.00000005 && i > 0) {
|
204 | y += this._lineBreadths[row++] + this.spacing.height;
|
205 | x = xstart;
|
206 | if (row === this._lineLengths.length) row--;
|
207 | }
|
208 | const lastbr = this._lineBreadths[row];
|
209 | let h = (lastbr > 0) ? lastbr - marg.top - marg.bottom : 0;
|
210 | let ya = (lastbr > 0) ? y + marg.top : y;
|
211 | if ((lastbr > 0) && !this.isStretched(true, elem, panel)) {
|
212 | const align = this.align(elem, panel);
|
213 | ya += align.y * (h - mb.height) + align.offsetY;
|
214 | h = mb.height;
|
215 | }
|
216 | const xa = x + ((lastbr > 0) ? marg.left : 0);
|
217 | this.arrangeElement(elem, xa, ya, mb.width, h);
|
218 | x += gw + this.spacing.width;
|
219 | }
|
220 | } else if (this.direction === 180) {
|
221 | let row = 0;
|
222 | for (let i = 0; i < elements.length; i++) {
|
223 | const elem = elements[i];
|
224 | if (!elem.visible) continue;
|
225 | const mb = elem.measuredBounds;
|
226 | const marg = <go.Margin>elem.margin;
|
227 | const gw = marg.left + mb.width + marg.right;
|
228 | if (x - gw - pad.left < 0.00000005 && i > 0) {
|
229 | y += this._lineBreadths[row++] + this.spacing.height;
|
230 | x = xstart;
|
231 | if (row === this._lineLengths.length) row--;
|
232 | }
|
233 | const lastbr = this._lineBreadths[row];
|
234 | let h = (lastbr > 0) ? lastbr - marg.top - marg.bottom : 0;
|
235 | let ya = (lastbr > 0) ? y + marg.top : y;
|
236 | if ((lastbr > 0) && !this.isStretched(true, elem, panel)) {
|
237 | const align = this.align(elem, panel);
|
238 | ya += align.y * (h - mb.height) + align.offsetY;
|
239 | h = mb.height;
|
240 | }
|
241 | const xa = x - gw + ((lastbr > 0) ? marg.left : 0);
|
242 | this.arrangeElement(elem, xa, ya, mb.width, h);
|
243 | x -= gw + this.spacing.width;
|
244 | }
|
245 | } else if (this.direction === 90) {
|
246 | let col = 0;
|
247 | for (let i = 0; i < elements.length; i++) {
|
248 | const elem = elements[i];
|
249 | if (!elem.visible) continue;
|
250 | const mb = elem.measuredBounds;
|
251 | const marg = <go.Margin>elem.margin;
|
252 | const gh = marg.top + mb.height + marg.bottom;
|
253 | if (y - pad.top > this._lineLengths[col] - 0.00000005 && i > 0) {
|
254 | x += this._lineBreadths[col++] + this.spacing.width;
|
255 | y = ystart;
|
256 | if (col === this._lineLengths.length) col--;
|
257 | }
|
258 | const lastbr = this._lineBreadths[col];
|
259 | let w = (lastbr > 0) ? lastbr - marg.left - marg.right : 0;
|
260 | let xa = (lastbr > 0) ? x + marg.left : x;
|
261 | if ((lastbr > 0) && !this.isStretched(false, elem, panel)) {
|
262 | const align = this.align(elem, panel);
|
263 | xa += align.x * (w - mb.width) + align.offsetX;
|
264 | w = mb.width;
|
265 | }
|
266 | const ya = y + ((lastbr > 0) ? marg.top : 0);
|
267 | this.arrangeElement(elem, xa, ya, w, mb.height);
|
268 | y += gh + this.spacing.height;
|
269 | }
|
270 | } else if (this.direction === 270) {
|
271 | let col = 0;
|
272 | for (let i = 0; i < elements.length; i++) {
|
273 | const elem = elements[i];
|
274 | if (!elem.visible) continue;
|
275 | const mb = elem.measuredBounds;
|
276 | const marg = <go.Margin>elem.margin;
|
277 | const gh = marg.top + mb.height + marg.bottom;
|
278 | if (y - gh - pad.top < 0.00000005 && i > 0) {
|
279 | x += this._lineBreadths[col++] + this.spacing.width;
|
280 | y = ystart - gh;
|
281 | if (col === this._lineLengths.length) col--;
|
282 | } else {
|
283 | y -= gh;
|
284 | }
|
285 | const lastbr = this._lineBreadths[col];
|
286 | let w = (lastbr > 0) ? lastbr - marg.left - marg.right : 0;
|
287 | let xa = (lastbr > 0) ? x + marg.left : x;
|
288 | if ((lastbr > 0) && !this.isStretched(false, elem, panel)) {
|
289 | const align = this.align(elem, panel);
|
290 | xa += align.x * (w - mb.width) + align.offsetX;
|
291 | w = mb.width;
|
292 | }
|
293 | const ya = y + ((lastbr > 0) ? marg.top : 0);
|
294 | this.arrangeElement(elem, xa, ya, w, mb.height);
|
295 | y -= this.spacing.height;
|
296 | }
|
297 | }
|
298 | }
|
299 |
|
300 | private static _ = (() => {
|
301 | go.Panel.definePanelLayout('Flow', new PanelLayoutFlow());
|
302 | })();
|
303 | }
|
304 |
|
\ | No newline at end of file |