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