1 /*
2 * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3 *
4 * See the LICENSE file for terms of use.
5 */
6
7 #include "Wt/WRectF.h"
8
9 #include <algorithm>
10
11 #include "Wt/WLogger.h"
12 #include "Wt/WPainterPath.h"
13 #include "Wt/WPointF.h"
14 #include "Wt/WStringStream.h"
15
16 #include "Wt/Json/Array.h"
17 #include "Wt/Json/Value.h"
18
19 #include "web/WebUtils.h"
20
21 namespace Wt {
22
23 LOGGER("WRectF");
24
WRectF()25 WRectF::WRectF()
26 : x_(0), y_(0), width_(0), height_(0)
27 { }
28
WRectF(double x,double y,double width,double height)29 WRectF::WRectF(double x, double y, double width, double height)
30 : x_(x), y_(y), width_(width), height_(height)
31 { }
32
WRectF(const WPointF & topLeft,const WPointF & bottomRight)33 WRectF::WRectF(const WPointF& topLeft, const WPointF& bottomRight)
34 : x_(topLeft.x()),
35 y_(topLeft.y()),
36 width_(bottomRight.x() - topLeft.x()),
37 height_(bottomRight.y() - topLeft.y())
38 { }
39
WRectF(const WRectF & other)40 WRectF::WRectF(const WRectF& other)
41 : WJavaScriptExposableObject(other),
42 x_(other.x()),
43 y_(other.y()),
44 width_(other.width()),
45 height_(other.height())
46 { }
47
48 #ifdef WT_TARGET_JAVA
49 WRectF& WRectF::operator=(const WRectF& rhs)
50 {
51 WJavaScriptExposableObject::operator=(rhs);
52
53 x_ = rhs.x_;
54 y_ = rhs.y_;
55 width_ = rhs.width_;
56 height_ = rhs.height_;
57
58 return *this;
59 }
60 #endif // WT_TARGET_JAVA
61
62 #ifdef WT_TARGET_JAVA
clone()63 WRectF WRectF::clone() const
64 {
65 return WRectF(*this);
66 }
67 #endif
68
~WRectF()69 WRectF::~WRectF()
70 { }
71
72 bool WRectF::operator==(const WRectF& rhs) const
73 {
74 if (!sameBindingAs(rhs)) return false;
75
76 return
77 x_ == rhs.x_
78 && y_ == rhs.y_
79 && width_ == rhs.width_
80 && height_ == rhs.height_;
81 }
82
83 bool WRectF::operator!=(const WRectF& rhs) const
84 {
85 return !(*this == rhs);
86 }
87
88 #ifndef WT_TARGET_JAVA
isNull()89 bool WRectF::isNull() const
90 {
91 if (isJavaScriptBound()) return false;
92
93 return x_ == 0 && y_ == 0 && width_ == 0 && height_ == 0;
94 }
95 #endif //WT_TARGET_JAVA
96
isEmpty()97 bool WRectF::isEmpty() const
98 {
99 if (isJavaScriptBound()) return false;
100
101 return width_ == 0 && height_ == 0;
102 }
103
setX(double x)104 void WRectF::setX(double x)
105 {
106 checkModifiable();
107 width_ += (x_ - x);
108 x_ = x;
109 }
110
setY(double y)111 void WRectF::setY(double y)
112 {
113 checkModifiable();
114 height_ += (y_ - y);
115 y_ = y;
116 }
117
center()118 WPointF WRectF::center() const
119 {
120 return WPointF(x_ + width_/2, y_ + height_/2);
121 }
122
topLeft()123 WPointF WRectF::topLeft() const
124 {
125 return WPointF(x_, y_);
126 }
127
topRight()128 WPointF WRectF::topRight() const
129 {
130 return WPointF(x_ + width_, y_);
131 }
132
bottomLeft()133 WPointF WRectF::bottomLeft() const
134 {
135 return WPointF(x_, y_ + height_);
136 }
137
bottomRight()138 WPointF WRectF::bottomRight() const
139 {
140 return WPointF(x_ + width_, y_ + height_);
141 }
142
contains(double x,double y)143 bool WRectF::contains(double x, double y) const
144 {
145 return x >= x_ && x <= (x_ + width_) && y >= y_ && y <= (y_ + height_);
146 }
147
contains(const WPointF & p)148 bool WRectF::contains(const WPointF& p) const
149 {
150 return contains(p.x(), p.y());
151 }
152
intersects(const WRectF & other)153 bool WRectF::intersects(const WRectF& other) const
154 {
155 if (isEmpty() || other.isEmpty())
156 return false;
157 else {
158 WRectF r1 = normalized();
159 WRectF r2 = other.normalized();
160
161 bool intersectX = (r2.left() >= r1.left() && r2.left() <= r1.right())
162 || (r2.right() >= r1.left() && r2.right() <= r1.right());
163
164 bool intersectY = (r2.top() >= r1.top() && r2.top() <= r1.bottom())
165 || (r2.bottom() >= r1.top() && r2.bottom() <= r1.bottom());
166
167 return intersectX && intersectY;
168 }
169 }
170
united(const WRectF & other)171 WRectF WRectF::united(const WRectF& other) const
172 {
173 if (isEmpty())
174 return other;
175 else if (other.isEmpty())
176 return *this;
177 else {
178 WRectF r1 = normalized();
179 WRectF r2 = other.normalized();
180
181 double l = std::min(r1.left(), r2.left());
182 double r = std::max(r1.right(), r2.right());
183 double t = std::min(r1.top(), r2.top());
184 double b = std::max(r1.bottom(), r2.bottom());
185
186 return WRectF(l, t, r - l, b - t);
187 }
188 }
189
normalized()190 WRectF WRectF::normalized() const
191 {
192 double x, y, w, h;
193
194 if (width_ > 0) {
195 x = x_;
196 w = width_;
197 } else {
198 x = x_ + width_;
199 w = -width_;
200 }
201
202 if (height_ > 0) {
203 y = y_;
204 h = height_;
205 } else {
206 y = y_ + height_;
207 h = -height_;
208 }
209
210 WRectF result(x, y, w, h);
211 if (isJavaScriptBound()) {
212 result.assignBinding(*this,
213 WT_CLASS ".gfxUtils.rect_normalized(" + jsRef() + ')');
214 }
215 return result;
216 }
217
jsValue()218 std::string WRectF::jsValue() const
219 {
220 char buf[30];
221 WStringStream ss;
222 ss << '[';
223 ss << Utils::round_js_str(x_, 3, buf) << ',';
224 ss << Utils::round_js_str(y_, 3, buf) << ',';
225 ss << Utils::round_js_str(width_, 3, buf) << ',';
226 ss << Utils::round_js_str(height_, 3, buf) << ']';
227 return ss.str();
228 }
229
assignFromJSON(const Json::Value & value)230 void WRectF::assignFromJSON(const Json::Value &value)
231 {
232 try {
233 #ifndef WT_TARGET_JAVA
234 const Json::Array &ar = value;
235 #else
236 const Json::Array &ar = static_cast<Json::Array&>(value);
237 #endif
238 if (ar.size() == 4 &&
239 !ar[0].toNumber().isNull() &&
240 !ar[1].toNumber().isNull() &&
241 !ar[2].toNumber().isNull() &&
242 !ar[3].toNumber().isNull()) {
243 x_ = ar[0].toNumber().orIfNull(x_);
244 y_ = ar[1].toNumber().orIfNull(y_);
245 width_ = ar[2].toNumber().orIfNull(width_);
246 height_ = ar[3].toNumber().orIfNull(height_);
247 } else {
248 LOG_ERROR("Couldn't convert JSON to WRectF");
249 }
250 } catch (std::exception &e) {
251 LOG_ERROR("Couldn't convert JSON to WRectF: " + std::string(e.what()));
252 }
253 }
254
toPath()255 WPainterPath WRectF::toPath() const
256 {
257 WPainterPath path(WPointF(x_, y_));
258
259 path.lineTo(x_ + width_, y_);
260 path.lineTo(x_ + width_, y_ + height_);
261 path.lineTo(x_, y_ + height_);
262 path.closeSubPath();
263
264 return path;
265 }
266
267 }
268