1// Aseprite
2// Copyright (C) 2019 Igara Studio S.A.
3// Copyright (C) 2017-2018 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/script/luacpp.h"
13#include "fmt/format.h"
14#include "gfx/point.h"
15#include "gfx/rect.h"
16
17namespace app {
18namespace script {
19
20namespace {
21
22gfx::Rect Rectangle_new(lua_State* L, int index)
23{
24 gfx::Rect rc(0, 0, 0, 0);
25 // Copy other rectangle
26 if (auto rc2 = may_get_obj<gfx::Rect>(L, index)) {
27 rc = *rc2;
28 }
29 // Convert { x, y, width, height } into a Rectangle
30 else if (lua_istable(L, index)) {
31 const int type = lua_getfield(L, index, "x");
32 if (VALID_LUATYPE(type)) {
33 lua_getfield(L, index, "y");
34 lua_getfield(L, index, "width");
35 lua_getfield(L, index, "height");
36 rc.x = lua_tointeger(L, -4);
37 rc.y = lua_tointeger(L, -3);
38 rc.w = lua_tointeger(L, -2);
39 rc.h = lua_tointeger(L, -1);
40 lua_pop(L, 4);
41 }
42 else {
43 lua_pop(L, 1);
44 lua_geti(L, index, 1);
45 lua_geti(L, index, 2);
46 lua_geti(L, index, 3);
47 lua_geti(L, index, 4);
48 rc.x = lua_tointeger(L, -4);
49 rc.y = lua_tointeger(L, -3);
50 rc.w = lua_tointeger(L, -2);
51 rc.h = lua_tointeger(L, -1);
52 lua_pop(L, 4);
53 }
54 }
55 else {
56 rc.x = lua_tointeger(L, index);
57 rc.y = lua_tointeger(L, index+1);
58 rc.w = lua_tointeger(L, index+2);
59 rc.h = lua_tointeger(L, index+3);
60 }
61 return rc;
62}
63
64int Rectangle_new(lua_State* L)
65{
66 push_obj(L, Rectangle_new(L, 1));
67 return 1;
68}
69
70int Rectangle_gc(lua_State* L)
71{
72 get_obj<gfx::Rect>(L, 1)->~RectT();
73 return 0;
74}
75
76int Rectangle_eq(lua_State* L)
77{
78 const auto a = get_obj<gfx::Rect>(L, 1);
79 const auto b = get_obj<gfx::Rect>(L, 2);
80 lua_pushboolean(L, *a == *b);
81 return 1;
82}
83
84int Rectangle_tostring(lua_State* L)
85{
86 const auto rc = get_obj<gfx::Rect>(L, 1);
87 lua_pushstring(L, fmt::format("Rectangle{{ x={}, y={}, width={}, height={} }}",
88 rc->x, rc->y, rc->w, rc->h).c_str());
89 return 1;
90}
91
92int Rectangle_contains(lua_State* L)
93{
94 const auto a = get_obj<gfx::Rect>(L, 1);
95 const auto b = get_obj<gfx::Rect>(L, 2);
96 lua_pushboolean(L, a->contains(*b));
97 return 1;
98}
99
100int Rectangle_intersects(lua_State* L)
101{
102 const auto a = get_obj<gfx::Rect>(L, 1);
103 const auto b = get_obj<gfx::Rect>(L, 2);
104 lua_pushboolean(L, a->intersects(*b));
105 return 1;
106}
107
108int Rectangle_union(lua_State* L)
109{
110 const auto a = get_obj<gfx::Rect>(L, 1);
111 const auto b = get_obj<gfx::Rect>(L, 2);
112 push_obj(L, a->createUnion(*b));
113 return 1;
114}
115
116int Rectangle_intersect(lua_State* L)
117{
118 const auto a = get_obj<gfx::Rect>(L, 1);
119 const auto b = get_obj<gfx::Rect>(L, 2);
120 push_obj(L, a->createIntersection(*b));
121 return 1;
122}
123
124int Rectangle_get_x(lua_State* L)
125{
126 const auto rc = get_obj<gfx::Rect>(L, 1);
127 lua_pushinteger(L, rc->x);
128 return 1;
129}
130
131int Rectangle_get_y(lua_State* L)
132{
133 const auto rc = get_obj<gfx::Rect>(L, 1);
134 lua_pushinteger(L, rc->y);
135 return 1;
136}
137
138int Rectangle_get_width(lua_State* L)
139{
140 const auto rc = get_obj<gfx::Rect>(L, 1);
141 lua_pushinteger(L, rc->w);
142 return 1;
143}
144
145int Rectangle_get_height(lua_State* L)
146{
147 const auto rc = get_obj<gfx::Rect>(L, 1);
148 lua_pushinteger(L, rc->h);
149 return 1;
150}
151
152int Rectangle_set_x(lua_State* L)
153{
154 auto rc = get_obj<gfx::Rect>(L, 1);
155 rc->x = lua_tointeger(L, 2);
156 return 0;
157}
158
159int Rectangle_set_y(lua_State* L)
160{
161 auto rc = get_obj<gfx::Rect>(L, 1);
162 rc->y = lua_tointeger(L, 2);
163 return 0;
164}
165
166int Rectangle_set_width(lua_State* L)
167{
168 auto rc = get_obj<gfx::Rect>(L, 1);
169 rc->w = lua_tointeger(L, 2);
170 return 0;
171}
172
173int Rectangle_set_height(lua_State* L)
174{
175 auto rc = get_obj<gfx::Rect>(L, 1);
176 rc->h = lua_tointeger(L, 2);
177 return 0;
178}
179
180int Rectangle_get_isEmpty(lua_State* L)
181{
182 const auto rc = get_obj<gfx::Rect>(L, 1);
183 lua_pushboolean(L, rc->isEmpty());
184 return 1;
185}
186
187const luaL_Reg Rectangle_methods[] = {
188 { "__gc", Rectangle_gc },
189 { "__eq", Rectangle_eq },
190 { "__tostring", Rectangle_tostring },
191 { "__band", Rectangle_intersect },
192 { "__bor", Rectangle_union },
193 { "contains", Rectangle_contains },
194 { "intersects", Rectangle_intersects },
195 { "union", Rectangle_union },
196 { "intersect", Rectangle_intersect },
197 { nullptr, nullptr }
198};
199
200const Property Rectangle_properties[] = {
201 { "x", Rectangle_get_x, Rectangle_set_x },
202 { "y", Rectangle_get_y, Rectangle_set_y },
203 { "width", Rectangle_get_width, Rectangle_set_width },
204 { "height", Rectangle_get_height, Rectangle_set_height },
205 { "isEmpty", Rectangle_get_isEmpty, nullptr },
206 { nullptr, nullptr, nullptr }
207};
208
209} // anonymous namespace
210
211DEF_MTNAME(gfx::Rect);
212
213void register_rect_class(lua_State* L)
214{
215 using Rectangle = gfx::Rect;
216 REG_CLASS(L, Rectangle);
217 REG_CLASS_NEW(L, Rectangle);
218 REG_CLASS_PROPERTIES(L, Rectangle);
219}
220
221gfx::Rect convert_args_into_rect(lua_State* L, int index)
222{
223 return Rectangle_new(L, index);
224}
225
226} // namespace script
227} // namespace app
228