1 /*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SampleCode.h"
9 #include "SkView.h"
10 #include "SkLua.h"
11 #include "SkCanvas.h"
12 #include "Resources.h"
13 #include "SkData.h"
14
15 extern "C" {
16 #include "lua.h"
17 #include "lualib.h"
18 #include "lauxlib.h"
19 }
20
21 //#define LUA_FILENAME "test.lua"
22 #define LUA_FILENAME "slides.lua"
23
24 static const char gDrawName[] = "onDrawContent";
25 static const char gClickName[] = "onClickHandler";
26 static const char gUnicharName[] = "onCharHandler";
27
28 static const char gLuaClickHandlerName[] = "lua-click-handler";
29
30 static const char gMissingCode[] = ""
31 "local paint = Sk.newPaint()"
32 "paint:setAntiAlias(true)"
33 "paint:setTextSize(30)"
34 ""
35 "function onDrawContent(canvas)"
36 " canvas:drawText('missing \"test.lua\"', 20, 50, paint)"
37 "end"
38 ;
39
40 class LuaView : public SampleView {
41 public:
LuaView()42 LuaView() : fLua(NULL) {}
43
~LuaView()44 virtual ~LuaView() {
45 SkDELETE(fLua);
46 }
47
setImageFilename(lua_State * L)48 void setImageFilename(lua_State* L) {
49 SkString str = GetResourcePath("mandrill_256.png");
50
51 lua_getglobal(L, "setImageFilename");
52 if (lua_isfunction(L, -1)) {
53 fLua->pushString(str.c_str());
54 if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
55 SkDebugf("lua err: %s\n", lua_tostring(L, -1));
56 }
57 }
58 }
59
ensureLua()60 lua_State* ensureLua() {
61 if (NULL == fLua) {
62 fLua = SkNEW(SkLua);
63
64 SkString str = GetResourcePath(LUA_FILENAME);
65 SkData* data = SkData::NewFromFileName(str.c_str());
66 if (data) {
67 fLua->runCode(data->data(), data->size());
68 data->unref();
69 this->setImageFilename(fLua->get());
70 } else {
71 fLua->runCode(gMissingCode);
72 }
73 }
74 return fLua->get();
75 }
76
77 protected:
onQuery(SkEvent * evt)78 bool onQuery(SkEvent* evt) override {
79 if (SampleCode::TitleQ(*evt)) {
80 SampleCode::TitleR(evt, "Lua");
81 return true;
82 }
83 SkUnichar uni;
84 if (SampleCode::CharQ(*evt, &uni)) {
85 lua_State* L = this->ensureLua();
86 lua_getglobal(L, gUnicharName);
87 if (lua_isfunction(L, -1)) {
88 SkString str;
89 str.appendUnichar(uni);
90 fLua->pushString(str.c_str());
91 if (lua_pcall(L, 1, 1, 0) != LUA_OK) {
92 SkDebugf("lua err: %s\n", lua_tostring(L, -1));
93 } else {
94 if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
95 this->inval(NULL);
96 return true;
97 }
98 }
99 }
100 }
101 return this->INHERITED::onQuery(evt);
102 }
103
onDrawContent(SkCanvas * canvas)104 void onDrawContent(SkCanvas* canvas) override {
105 lua_State* L = this->ensureLua();
106
107 lua_getglobal(L, gDrawName);
108 if (!lua_isfunction(L, -1)) {
109 int t = lua_type(L, -1);
110 SkDebugf("--- expected %s function %d, ignoring.\n", gDrawName, t);
111 lua_pop(L, 1);
112 } else {
113 // does it make sense to try to "cache" the lua version of this
114 // canvas between draws?
115 fLua->pushCanvas(canvas);
116 fLua->pushScalar(this->width());
117 fLua->pushScalar(this->height());
118 if (lua_pcall(L, 3, 1, 0) != LUA_OK) {
119 SkDebugf("lua err: %s\n", lua_tostring(L, -1));
120 } else {
121 if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
122 this->inval(NULL);
123 }
124 }
125 }
126 }
127
onFindClickHandler(SkScalar x,SkScalar y,unsigned modi)128 virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y,
129 unsigned modi) override {
130 lua_State* L = this->ensureLua();
131 lua_getglobal(L, gClickName);
132 if (lua_isfunction(L, -1)) {
133 fLua->pushScalar(x);
134 fLua->pushScalar(y);
135 fLua->pushString("down");
136 if (lua_pcall(L, 3, 1, 0) != LUA_OK) {
137 SkDebugf("lua err: %s\n", lua_tostring(L, -1));
138 } else {
139 if (lua_isboolean(L, -1) && lua_toboolean(L, -1)) {
140 this->inval(NULL);
141 Click* c = new Click(this);
142 c->setType(gLuaClickHandlerName);
143 return c;
144 }
145 }
146 }
147 return this->INHERITED::onFindClickHandler(x, y, modi);
148 }
149
onClick(Click * click)150 bool onClick(Click* click) override {
151 if (click->getType() != gLuaClickHandlerName) {
152 return this->INHERITED::onClick(click);
153 }
154
155 const char* state = NULL;
156 switch (click->fState) {
157 case Click::kMoved_State:
158 state = "moved";
159 break;
160 case Click::kUp_State:
161 state = "up";
162 break;
163 default:
164 break;
165 }
166 if (state) {
167 this->inval(NULL);
168 lua_State* L = fLua->get();
169 lua_getglobal(L, gClickName);
170 fLua->pushScalar(click->fCurr.x());
171 fLua->pushScalar(click->fCurr.y());
172 fLua->pushString(state);
173 lua_pcall(L, 3, 1, 0);
174 return lua_isboolean(L, -1) && lua_toboolean(L, -1);
175 }
176 return true;
177 }
178
179 private:
180 SkLua* fLua;
181
182 typedef SampleView INHERITED;
183 };
184
185 //////////////////////////////////////////////////////////////////////////////
186
MyFactory()187 static SkView* MyFactory() { return new LuaView; }
188 static SkViewRegister reg(MyFactory);
189