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/size.h"
15
16#include <cmath>
17
18namespace app {
19namespace script {
20
21namespace {
22
23gfx::Size Size_new(lua_State* L, int index)
24{
25 gfx::Size sz(0, 0);
26 // Copy other size
27 if (auto sz2 = may_get_obj<gfx::Size>(L, index)) {
28 sz = *sz2;
29 }
30 // Convert {x=int,y=int} or {int,int} into a Size
31 else if (lua_istable(L, index)) {
32 const int type = lua_getfield(L, index, "width");
33 if (VALID_LUATYPE(type)) {
34 lua_getfield(L, index, "height");
35 sz.w = lua_tointeger(L, -2);
36 sz.h = lua_tointeger(L, -1);
37 lua_pop(L, 2);
38 }
39 else {
40 lua_pop(L, 1);
41 lua_geti(L, index, 1);
42 lua_geti(L, index, 2);
43 sz.w = lua_tointeger(L, -2);
44 sz.h = lua_tointeger(L, -1);
45 lua_pop(L, 2);
46 }
47 }
48 else {
49 sz.w = lua_tointeger(L, index);
50 sz.h = lua_tointeger(L, index+1);
51 }
52 return sz;
53}
54
55int Size_new(lua_State* L)
56{
57 push_obj(L, Size_new(L, 1));
58 return 1;
59}
60
61int Size_gc(lua_State* L)
62{
63 get_obj<gfx::Size>(L, 1)->~SizeT();
64 return 0;
65}
66
67int Size_eq(lua_State* L)
68{
69 const auto a = get_obj<gfx::Size>(L, 1);
70 const auto b = get_obj<gfx::Size>(L, 2);
71 lua_pushboolean(L, *a == *b);
72 return 1;
73}
74
75int Size_tostring(lua_State* L)
76{
77 const auto sz = get_obj<gfx::Size>(L, 1);
78 lua_pushstring(L, fmt::format("Size{{ width={}, height={} }}",
79 sz->w, sz->h).c_str());
80 return 1;
81}
82
83int Size_unm(lua_State* L)
84{
85 const auto sz = get_obj<gfx::Size>(L, 1);
86 push_obj(L, -(*sz));
87 return 1;
88}
89
90int Size_add(lua_State* L)
91{
92 gfx::Size result(0, 0);
93 if (lua_isuserdata(L, 1))
94 result += *get_obj<gfx::Size>(L, 1);
95 else
96 result += lua_tointeger(L, 1);
97 if (lua_isuserdata(L, 2))
98 result += *get_obj<gfx::Size>(L, 2);
99 else
100 result += lua_tointeger(L, 2);
101 push_obj(L, result);
102 return 1;
103}
104
105int Size_sub(lua_State* L)
106{
107 gfx::Size result = *get_obj<gfx::Size>(L, 1);
108 if (lua_isuserdata(L, 2))
109 result -= *get_obj<gfx::Size>(L, 2);
110 else
111 result -= lua_tointeger(L, 2);
112 push_obj(L, result);
113 return 1;
114}
115
116int Size_mul(lua_State* L)
117{
118 gfx::Size result = *get_obj<gfx::Size>(L, 1);
119 result *= lua_tointeger(L, 2);
120 push_obj(L, result);
121 return 1;
122}
123
124int Size_div(lua_State* L)
125{
126 gfx::Size result = *get_obj<gfx::Size>(L, 1);
127 const int value = lua_tointeger(L, 2);
128 if (value == 0)
129 return luaL_error(L, "attempt to divide by zero");
130 result /= value;
131 push_obj(L, result);
132 return 1;
133}
134
135int Size_mod(lua_State* L)
136{
137 gfx::Size result = *get_obj<gfx::Size>(L, 1);
138 const int value = lua_tointeger(L, 2);
139 if (value == 0)
140 return luaL_error(L, "attempt to divide by zero");
141 result.w %= value;
142 result.h %= value;
143 push_obj(L, result);
144 return 1;
145}
146
147int Size_pow(lua_State* L)
148{
149 gfx::Size result = *get_obj<gfx::Size>(L, 1);
150 const int value = lua_tointeger(L, 2);
151 result.w = std::pow(result.w, value);
152 result.h = std::pow(result.h, value);
153 push_obj(L, result);
154 return 1;
155}
156
157int Size_get_width(lua_State* L)
158{
159 const auto sz = get_obj<gfx::Size>(L, 1);
160 ASSERT(sz);
161 lua_pushinteger(L, sz->w);
162 return 1;
163}
164
165int Size_get_height(lua_State* L)
166{
167 const auto sz = get_obj<gfx::Size>(L, 1);
168 ASSERT(sz);
169 lua_pushinteger(L, sz->h);
170 return 1;
171}
172
173int Size_set_width(lua_State* L)
174{
175 auto sz = get_obj<gfx::Size>(L, 1);
176 ASSERT(sz);
177 sz->w = lua_tointeger(L, 2);
178 return 0;
179}
180
181int Size_set_height(lua_State* L)
182{
183 auto sz = get_obj<gfx::Size>(L, 1);
184 ASSERT(sz);
185 sz->h = lua_tointeger(L, 2);
186 return 0;
187}
188
189const luaL_Reg Size_methods[] = {
190 { "__gc", Size_gc },
191 { "__eq", Size_eq },
192 { "__tostring", Size_tostring },
193 { "__unm", Size_unm },
194 { "__add", Size_add },
195 { "__sub", Size_sub },
196 { "__mul", Size_mul },
197 { "__div", Size_div },
198 { "__mod", Size_mod },
199 { "__pow", Size_pow },
200 { "__idiv", Size_div },
201 { nullptr, nullptr }
202};
203
204const Property Size_properties[] = {
205 { "width", Size_get_width, Size_set_width },
206 { "height", Size_get_height, Size_set_height },
207 { nullptr, nullptr, nullptr }
208};
209
210} // anonymous namespace
211
212DEF_MTNAME(gfx::Size);
213
214void register_size_class(lua_State* L)
215{
216 using gfx::Size;
217 REG_CLASS(L, Size);
218 REG_CLASS_NEW(L, Size);
219 REG_CLASS_PROPERTIES(L, Size);
220}
221
222gfx::Size convert_args_into_size(lua_State* L, int index)
223{
224 return Size_new(L, index);
225}
226
227} // namespace script
228} // namespace app
229