1 /*
2 *
3 * Copyright 2019, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include <teeui/button.h>
19 namespace teeui {
20
makeSquareAtOffset(const PxPoint & offset,const pxs & sideLength)21 ConvexObject<4> makeSquareAtOffset(const PxPoint& offset, const pxs& sideLength) {
22 return ConvexObject<4>({offset, offset + PxPoint{sideLength, .0},
23 offset + PxPoint{sideLength, sideLength},
24 offset + PxPoint{.0, sideLength}});
25 }
26
draw(const PixelDrawer & drawPixel,const Box<pxs> & bounds,const ConvexObjectInfo * coBegin,const ConvexObjectInfo * coEnd)27 Error ButtonImpl::draw(const PixelDrawer& drawPixel, const Box<pxs>& bounds,
28 const ConvexObjectInfo* coBegin, const ConvexObjectInfo* coEnd) {
29
30 using intpxs = Coordinate<px, int64_t>;
31 Box<intpxs> intBounds(bounds);
32
33 auto drawPixelBoundsEnforced = [&](uint32_t x, uint32_t y, Color color) -> Error {
34 if (!intBounds.contains(Point<intpxs>(x, y))) {
35 TEEUI_LOG << "Bounds: " << bounds << " Pixel: " << Point<pxs>(x, y) << ENDL;
36 return Error::OutOfBoundsDrawing;
37 }
38 return drawPixel(x, y, color);
39 };
40
41 auto drawBox = [&](const Box<intpxs>& box, Color c) -> Error {
42 for (int y = 0; y < box.h().count(); ++y) {
43 for (int x = 0; x < box.w().count(); ++x) {
44 if (auto error = drawPixel(box.x().count() + x, box.y().count() + y, c)) {
45 return error;
46 }
47 }
48 }
49 return Error::OK;
50 };
51
52 #ifdef DRAW_DEBUG_MARKERS
53 auto drawDebugBox = [&](const Box<pxs>& box, Color c) {
54 drawBox(box, (c & 0xffffff) | 0x40000000);
55 };
56
57 drawDebugBox(intBounds, 0xff);
58 #endif
59
60 intpxs intRadius = radius_.count();
61
62 TEEUI_LOG << intBounds << ENDL;
63
64 auto drawCorner = [&, this](intpxs right, intpxs bottom) -> Error {
65 Box<intpxs> cBounds(intBounds.x(), intBounds.y(), intRadius, intRadius);
66 cBounds.translateSelf(Point<intpxs>(right * (intBounds.w() - intRadius),
67 bottom * (intBounds.h() - intRadius)));
68 auto center = Point<pxs>((intpxs(1) - right) * intRadius, (intpxs(1) - bottom) * intRadius);
69 center += cBounds.topLeft();
70 center -= Point<pxs>(.5, .5);
71 TEEUI_LOG << "Radius: " << intRadius << " cBounds: " << cBounds << " center: " << center
72 << ENDL;
73 for (int y = 0; y < cBounds.h().count(); ++y) {
74 for (int x = 0; x < cBounds.w().count(); ++x) {
75 auto pos = Point<pxs>(cBounds.x().count() + x, cBounds.y().count() + y);
76 auto color = drawCirclePoint(center, intRadius, pos, color_);
77 if (auto error = drawPixelBoundsEnforced(pos.x().count(), pos.y().count(), color)) {
78 return error;
79 }
80 }
81 }
82 return Error::OK;
83 };
84
85 if (roundTopLeft_) {
86 if (auto error = drawCorner(0, 0)) return error;
87 } else {
88 if (auto error = drawBox(
89 Box<intpxs>(0, 0, intRadius, intRadius).translate(intBounds.topLeft()), color_)) {
90 return error;
91 }
92 }
93
94 if (roundTopRight_) {
95 if (auto error = drawCorner(1, 0)) return error;
96 } else {
97 if (auto error = drawBox(Box<intpxs>(intBounds.w() - intRadius, 0, intRadius, intRadius)
98 .translate(intBounds.topLeft()),
99 color_)) {
100 return error;
101 }
102 }
103
104 if (roundBottomLeft_) {
105 if (auto error = drawCorner(0, 1)) return error;
106 } else {
107 if (auto error = drawBox(Box<intpxs>(0, intBounds.h() - intRadius, intRadius, intRadius)
108 .translate(intBounds.topLeft()),
109 color_)) {
110 return error;
111 }
112 }
113
114 if (roundBottomRight_) {
115 if (auto error = drawCorner(1, 1)) return error;
116 } else {
117 if (auto error = drawBox(Box<intpxs>(intBounds.w() - intRadius, intBounds.h() - intRadius,
118 intRadius, intRadius)
119 .translate(intBounds.topLeft()),
120 color_)) {
121 return error;
122 }
123 }
124
125 auto centerbox = Box<intpxs>(intRadius, intRadius, intBounds.w() - intRadius - intRadius,
126 intBounds.h() - intRadius - intRadius)
127 .translate(intBounds.topLeft());
128
129 if (auto error = drawBox(centerbox, color_)) return error;
130
131 if (auto error =
132 drawBox(Box<intpxs>(0, intRadius, intRadius, intBounds.h() - intRadius - intRadius)
133 .translate(intBounds.topLeft()),
134 color_)) {
135 return error;
136 }
137 if (auto error =
138 drawBox(Box<intpxs>(intRadius, 0, intBounds.w() - intRadius - intRadius, intRadius)
139 .translate(intBounds.topLeft()),
140 color_)) {
141 return error;
142 }
143 if (auto error = drawBox(Box<intpxs>(intBounds.w() - intRadius, intRadius, intRadius,
144 intBounds.h() - intRadius - intRadius)
145 .translate(intBounds.topLeft()),
146 color_)) {
147 return error;
148 }
149 if (auto error = drawBox(Box<intpxs>(intRadius, intBounds.h() - intRadius,
150 intBounds.w() - intRadius - intRadius, intRadius)
151 .translate(intBounds.topLeft()),
152 color_)) {
153 return error;
154 }
155
156 bool hasCOs = coBegin != coEnd;
157 if (hasCOs) {
158 Box<pxs> coBBox = Box<pxs>::boundingBox(coBegin->begin, coBegin->end);
159 for (const auto& co : makeRange(coBegin + 1, coEnd)) {
160 coBBox = coBBox.merge(co.begin, co.end);
161 }
162
163 auto start = PxPoint{bounds.w() - coBBox.w(), bounds.h() - coBBox.h()} / pxs(2.0);
164 start += bounds.topLeft();
165
166 Box<intpxs> intBBox(start.x().floor(), start.y().floor(), 0, 0);
167 intBBox = intBBox.merge(
168 Point<intpxs>{(start.x() + coBBox.w()).ceil(), (start.y() + coBBox.h()).ceil()});
169
170 TEEUI_LOG << "coBBox: " << coBBox << ENDL;
171
172 TEEUI_LOG << "intBBox: " << intBBox << ENDL;
173 for (int64_t y = 0; y < intBBox.h().count(); ++y) {
174 for (int64_t x = 0; x < intBBox.w().count(); ++x) {
175 PxPoint offset = coBBox.topLeft() + PxPoint{x, y};
176 // The pixel is a square of width and height 1.0
177 auto thePixel = makeSquareAtOffset(offset, 1.0);
178 TEEUI_LOG << thePixel << ENDL;
179 pxs areaCovered = 0.0;
180 for (const auto& co : makeRange(coBegin, coEnd)) {
181 auto coveredRegion = thePixel.intersect<10>(co.begin, co.end);
182 if (coveredRegion) areaCovered += coveredRegion->area();
183 TEEUI_LOG << " region: " << (bool)coveredRegion << " area: " << areaCovered;
184 }
185 TEEUI_LOG << ENDL;
186 if (areaCovered > 1.0) areaCovered = 1.0;
187 TEEUI_LOG << "x: " << x << " y: " << y << " area: " << areaCovered << ENDL;
188 uint32_t intensity = 0xff * areaCovered.count();
189 if (auto error =
190 drawPixelBoundsEnforced(intBBox.x().count() + x, intBBox.y().count() + y,
191 intensity << 24 | (0xffffff & convexObjectColor_)))
192 return error;
193 }
194 }
195 }
196
197 return Error::OK;
198 }
199
200 } // namespace teeui
201