1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.composer.layout;
23
24 import static org.opencastproject.util.data.Monadics.mlist;
25
26 import org.opencastproject.util.data.Function;
27 import org.opencastproject.util.data.Tuple;
28
29 import java.util.List;
30
31 public final class LayoutManager {
32 private LayoutManager() {
33 }
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public static TwoShapeLayout twoShapeLayout(Dimension canvas,
49 Dimension upper,
50 Dimension lower,
51 TwoShapeLayouts.TwoShapeLayoutSpec spec) {
52 return new TwoShapeLayout(canvas,
53 calcLayout(canvas, upper, spec.getUpper()),
54 calcLayout(canvas, lower, spec.getLower()));
55 }
56
57 private static Layout calcLayout(Dimension canvas,
58 Dimension shape,
59 HorizontalCoverageLayoutSpec posSpec) {
60 final Dimension slice = new Dimension(limitMin(canvas.getWidth() * posSpec.getHorizontalCoverage(), 0),
61 canvas.getHeight());
62 final Dimension scaled = scaleToFit(slice, shape);
63 final AnchorOffset dist = posSpec.getAnchorOffset();
64 final Offset anchorOfReference = offset(dist.getReferenceAnchor(), canvas);
65 final Offset anchorOfReferring = offset(dist.getReferringAnchor(), scaled);
66 return new Layout(
67 scaled,
68 new Offset(limitMin(anchorOfReference.getX() + dist.getOffset().getX() - anchorOfReferring.getX(), 0),
69 limitMin(anchorOfReference.getY() + dist.getOffset().getY() - anchorOfReferring.getY(), 0)));
70 }
71
72 private static Layout calcLayout(Dimension canvas,
73 Dimension shape,
74 AbsolutePositionLayoutSpec posSpec) {
75 final AnchorOffset dist = posSpec.getAnchorOffset();
76 final Offset anchorOfReference = offset(dist.getReferenceAnchor(), canvas);
77 final Offset anchorOfReferring = offset(dist.getReferringAnchor(), shape);
78 return new Layout(
79 shape,
80 new Offset(limitMin(anchorOfReference.getX() + dist.getOffset().getX() - anchorOfReferring.getX(), 0),
81 limitMin(anchorOfReference.getY() + dist.getOffset().getY() - anchorOfReferring.getY(), 0)));
82 }
83
84
85
86
87
88
89
90
91
92
93 public static MultiShapeLayout multiShapeLayout(final Dimension canvas,
94 final List<Tuple<Dimension, HorizontalCoverageLayoutSpec>> shapes) {
95 return new MultiShapeLayout(
96 canvas,
97 mlist(shapes).map(new Function<Tuple<Dimension, HorizontalCoverageLayoutSpec>, Layout>() {
98 @Override public Layout apply(Tuple<Dimension, HorizontalCoverageLayoutSpec> a) {
99 return calcLayout(canvas, a.getA(), a.getB());
100 }
101 }).value());
102 }
103
104
105
106
107
108
109
110
111
112
113 public static MultiShapeLayout absoluteMultiShapeLayout(
114 final Dimension canvas,
115 final List<Tuple<Dimension, AbsolutePositionLayoutSpec>> shapes) {
116 return new MultiShapeLayout(
117 canvas,
118 mlist(shapes).map(new Function<Tuple<Dimension, AbsolutePositionLayoutSpec>, Layout>() {
119 @Override public Layout apply(Tuple<Dimension, AbsolutePositionLayoutSpec> a) {
120 return calcLayout(canvas, a.getA(), a.getB());
121 }
122 }).value());
123 }
124
125 public static int limitMax(double v, int max) {
126 return (int) Math.min(Math.round(v), max);
127 }
128
129 public static int limitMin(double v, int min) {
130 return (int) Math.max(Math.round(v), min);
131 }
132
133
134 public static boolean fits(Dimension into, Dimension shape) {
135 return shape.getHeight() <= into.getHeight() && shape.getWidth() <= into.getHeight();
136 }
137
138
139 public static int area(Dimension a) {
140 return a.getWidth() * a.getHeight();
141 }
142
143
144 public static Dimension max(Dimension a, Dimension b) {
145 return area(a) > area(b) ? a : b;
146 }
147
148
149 public static double aspectRatio(Dimension a) {
150 return d(a.getWidth()) / d(a.getHeight());
151 }
152
153
154 public static boolean overlap(Layout a, Layout b) {
155 return (between(left(a), right(a), left(b)) || between(left(a), right(a), right(b)))
156 && (between(top(a), bottom(a), top(b)) || between(top(a), bottom(a), bottom(b)));
157 }
158
159
160 public static int left(Layout a) {
161 return a.getOffset().getX();
162 }
163
164
165 public static int right(Layout a) {
166 return a.getOffset().getX() + a.getDimension().getWidth();
167 }
168
169
170 public static int top(Layout a) {
171 return a.getOffset().getY();
172 }
173
174
175 public static int bottom(Layout a) {
176 return a.getOffset().getY() + a.getDimension().getHeight();
177 }
178
179
180 public static Offset offset(Anchor a, Dimension dim) {
181 return new Offset(limitMax(a.getLeft() * d(dim.getWidth()), dim.getWidth()),
182 limitMax(a.getTop() * d(dim.getHeight()), dim.getHeight()));
183 }
184
185
186
187
188
189 public static Dimension scale(Dimension limit, Dimension shape, double scale) {
190 return Dimension.dimension(
191 limitMax(d(shape.getWidth()) * scale, limit.getWidth()),
192 limitMax(d(shape.getHeight()) * scale, limit.getHeight()));
193 }
194
195
196 public static Dimension scaleToFit(Dimension canvas, Dimension d) {
197 final double scaleToWidth = d(canvas.getWidth()) / d(d.getWidth());
198 if (d.getHeight() * scaleToWidth > canvas.getHeight()) {
199 final double scaleToHeight = d(canvas.getHeight()) / d(d.getHeight());
200 return scale(canvas, d, scaleToHeight);
201 } else {
202 return scale(canvas, d, scaleToWidth);
203 }
204 }
205
206
207 public static boolean between(int a, int b, int x) {
208 return a <= x && x <= b;
209 }
210
211 private static double d(int v) {
212 return v;
213 }
214 }