// -------------------------------------------------------------------- // Lua bindings for user interface // -------------------------------------------------------------------- /* This file is part of the extensible drawing editor Ipe. Copyright (c) 1993-2020 Otfried Cheong Ipe is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. As a special exception, you have permission to link Ipe with the CGAL library and distribute executables, as long as you follow the requirements of the Gnu General Public License in regard to all of the software in the executable aside from CGAL. Ipe is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Ipe; if not, you can find it at "http://www.gnu.org/copyleft/gpl.html", or write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "appui.h" #include "ipecanvas.h" #include "tools.h" #include "ipelua.h" #include "ipethumbs.h" #include #include using namespace ipe; using namespace ipelua; // -------------------------------------------------------------------- static CanvasBase *check_canvas(lua_State *L, int i) { AppUiBase **ui = (AppUiBase **) luaL_checkudata(L, i, "Ipe.appui"); return (*ui)->canvas(); } inline AppUiBase **check_appui(lua_State *L, int i) { return (AppUiBase **) luaL_checkudata(L, i, "Ipe.appui"); } static int appui_tostring(lua_State *L) { check_appui(L, 1); lua_pushfstring(L, "AppUi@%p", lua_topointer(L, 1)); return 1; } /* When the Lua model is collected, its "ui" userdata will be garbage collected as well. At this point, the C++ object has long been deleted. */ static int appui_destructor(lua_State *L) { check_appui(L, 1); ipeDebug("AppUi Lua destructor"); return 0; } // -------------------------------------------------------------------- static int appui_setPage(lua_State *L) { AppUiBase **ui = check_appui(L, 1); Page *page = check_page(L, 2)->page; int pno = luaL_checkinteger(L, 3) - 1; int view = check_viewno(L, 4, page); Cascade *sheets = check_cascade(L, 5)->cascade; (*ui)->canvas()->setPage(page, pno, view, sheets); return 0; } static int appui_setResources(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); Document **d = check_document(L, 2); const PdfResources *res = (*d)->resources(); canvas->setResources(res); return 0; } static int appui_pan(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); Vector p = canvas->pan(); push_vector(L, p); return 1; } static int appui_setPan(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); Vector *v = check_vector(L, 2); canvas->setPan(*v); return 0; } static int appui_zoom(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); lua_pushnumber(L, canvas->zoom()); return 1; } static int appui_setZoom(lua_State *L) { AppUiBase **ui = check_appui(L, 1); (*ui)->setZoom(luaL_checknumber(L, 2)); return 0; } static int appui_setSnapIndicator(lua_State *L) { AppUiBase **ui = check_appui(L, 1); (*ui)->setSnapIndicator(luaL_checklstring(L, 2, nullptr)); return 0; } static int appui_pos(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); push_vector(L, canvas->pos()); return 1; } static int appui_globalPos(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); push_vector(L, canvas->globalPos()); return 1; } static int appui_unsnappedPos(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); push_vector(L, canvas->unsnappedPos()); return 1; } static int appui_simpleSnapPos(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); push_vector(L, canvas->simpleSnapPos()); return 1; } static int appui_setFifiVisible(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); canvas->setFifiVisible(lua_toboolean(L, 2)); return 0; } static int appui_setInkMode(lua_State *L) { AppUiBase **ui = check_appui(L, 1); bool ink = lua_toboolean(L, 2); (*ui)->setInkMode(ink); (*ui)->canvas()->setInkMode(ink); return 0; } static int appui_setSelectionVisible(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); canvas->setSelectionVisible(lua_toboolean(L, 2)); return 0; } static int appui_setSnap(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); Snap snap = canvas->snap(); get_snap(L, 2, snap); canvas->setSnap(snap); return 0; } static int appui_setAutoOrigin(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); Vector *v = check_vector(L, 2); canvas->setAutoOrigin(*v); return 0; } static int appui_update(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); if (lua_isnone(L, 2) || lua_isboolean(L, 2)) { if (lua_isnone(L, 2) || lua_toboolean(L, 2)) canvas->update(); else canvas->updateTool(); } else { ipe::Rect *r = check_rect(L, 2); Vector bl = canvas->userToDev(r->topLeft()); Vector tr = canvas->userToDev(r->bottomRight()); canvas->invalidate(int(bl.x-1), int(bl.y-1), int(tr.x - bl.x + 2), int(tr.y - bl.y + 2)); } return 0; } static int appui_finishTool(lua_State *L) { AppUiBase **ui = check_appui(L, 1); (*ui)->canvas()->finishTool(); (*ui)->explain("", 0); return 0; } static int appui_canvasSize(lua_State *L) { AppUiBase **ui = check_appui(L, 1); CanvasBase *canvas = (*ui)->canvas(); push_vector(L, Vector(canvas->canvasWidth(), canvas->canvasHeight())); lua_pushinteger(L, (*ui)->dpi()); return 2; } static void check_rgb(lua_State *L, int i, int &r, int &g, int &b) { r = int(1000 * luaL_checknumber(L, i) + 0.5); g = int(1000 * luaL_checknumber(L, i+1) + 0.5); b = int(1000 * luaL_checknumber(L, i+2) + 0.5); luaL_argcheck(L, (0 <= r && r <= 1000 && 0 <= g && g <= 1000 && 0 <= b && b <= 1000), 2, "color components must be between 0.0 and 1.0"); } static int appui_setCursor(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); if (lua_isnumber(L, 2)) { double s = lua_tonumberx(L, 2, nullptr); int r, g, b; check_rgb(L, 3, r, g, b); Color color(r, g, b); canvas->setCursor(CanvasBase::EDotCursor, s, &color); } else if (lua_isstring(L, 2)) { static const char * const cursor_names[] = { "standard", "hand", "cross", nullptr }; CanvasBase::TCursor t = CanvasBase::TCursor(luaL_checkoption(L, 2, nullptr, cursor_names)); canvas->setCursor(t); } else canvas->setCursor(CanvasBase::EStandardCursor); return 0; } static int appui_setNumbering(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); bool t = lua_toboolean(L, 2); CanvasBase::Style s = canvas->canvasStyle(); s.numberPages = t; canvas->setCanvasStyle(s); return 0; } static int appui_setPretty(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); bool t = lua_toboolean(L, 2); CanvasBase::Style s = canvas->canvasStyle(); s.pretty = t; canvas->setCanvasStyle(s); return 0; } static int appui_setScreen(lua_State *L) { AppUiBase **ui = check_appui(L, 1); static const char * const screen_names[] = { "normal", "maximized", "full", nullptr }; int t = luaL_checkoption(L, 2, nullptr, screen_names); (*ui)->setFullScreen(t); return 0; } static int appui_type3Font(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); lua_pushboolean(L, canvas->type3Font()); return 1; } // -------------------------------------------------------------------- static int appui_pantool(lua_State *L) { ipeDebug("pantool"); CanvasBase *canvas = check_canvas(L, 1); Page *page = check_page(L, 2)->page; int view = check_viewno(L, 3, page); PanTool *tool = new PanTool(canvas, page, view); canvas->setTool(tool); return 0; } static int appui_selecttool(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); Page *page = check_page(L, 2)->page; int view = check_viewno(L, 3, page); double selectDistance = luaL_checknumber(L, 4); bool nonDestructive = lua_toboolean(L, 5); SelectTool *tool = new SelectTool(canvas, page, view, selectDistance, nonDestructive); canvas->setTool(tool); return 0; } static int appui_transformtool(lua_State *L) { static const char * const option_names[] = { "translate", "scale", "stretch", "rotate", "shear", nullptr }; CanvasBase *canvas = check_canvas(L, 1); Page *page = check_page(L, 2)->page; int view = check_viewno(L, 3, page); int type = luaL_checkoption(L, 4, nullptr, option_names); bool withShift = lua_toboolean(L, 5); lua_pushvalue(L, 6); int method = luaL_ref(L, LUA_REGISTRYINDEX); IpeTransformTool *tool = new IpeTransformTool(canvas, page, view, TransformTool::TType(type), withShift, L, method); if (tool->isValid()) { canvas->setTool(tool); lua_pushboolean(L, true); return 1; } else { delete tool; return 0; } } static int luatool_setcolor(lua_State *L) { LuaTool *tool = (LuaTool *) lua_touserdata(L, lua_upvalueindex(1)); int r, g, b; check_rgb(L, 1, r, g, b); tool->setColor(Color(r, g, b)); return 0; } static int shapetool_setshape(lua_State *L) { ShapeTool *tool = (ShapeTool *) lua_touserdata(L, lua_upvalueindex(1)); Shape shape = check_shape(L, 1); int which = 0; if (!lua_isnoneornil(L, 2)) which = (int)luaL_checkinteger(L, 2); double pen = 1.0; if (lua_isnumber(L, 3)) pen = luaL_checknumber(L, 3); tool->setShape(shape, which, pen); return 0; } static int shapetool_setsnapping(lua_State *L) { ShapeTool *tool = (ShapeTool *) lua_touserdata(L, lua_upvalueindex(1)); bool snap = lua_toboolean(L, 1); bool skipLast = lua_toboolean(L, 2); tool->setSnapping(snap, skipLast); return 0; } static int shapetool_setmarks(lua_State *L) { ShapeTool *tool = (ShapeTool *) lua_touserdata(L, lua_upvalueindex(1)); luaL_argcheck(L, lua_istable(L, 1), 1, "argument is not a table"); int no = lua_rawlen(L, 1); tool->clearMarks(); for (int i = 1; i + 1 <= no; i += 2) { lua_rawgeti(L, 1, i); luaL_argcheck(L, is_type(L, -1, "Ipe.vector"), 1, "element is not a vector"); Vector *v = check_vector(L, -1); lua_rawgeti(L, 1, i+1); luaL_argcheck(L, lua_isnumber(L, -1), 1, "element is not a number"); int t = lua_tointegerx(L, -1, nullptr); luaL_argcheck(L, ShapeTool::EVertex <= t && t < ShapeTool::ENumMarkTypes, 1, "number is not a mark type"); lua_pop(L, 2); // v, t tool->addMark(*v, ShapeTool::TMarkType(t)); } return 0; } static int pastetool_setmatrix(lua_State *L) { PasteTool *tool = (PasteTool *) lua_touserdata(L, lua_upvalueindex(1)); Matrix *m = check_matrix(L, 1); tool->setMatrix(*m); return 0; } static int appui_shapetool(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); lua_pushvalue(L, 2); int luatool = luaL_ref(L, LUA_REGISTRYINDEX); ShapeTool *tool = new ShapeTool(canvas, L, luatool); // add methods to Lua tool lua_rawgeti(L, LUA_REGISTRYINDEX, luatool); lua_pushlightuserdata(L, tool); lua_pushcclosure(L, luatool_setcolor, 1); lua_setfield(L, -2, "setColor"); lua_pushlightuserdata(L, tool); lua_pushcclosure(L, shapetool_setshape, 1); lua_setfield(L, -2, "setShape"); lua_pushlightuserdata(L, tool); lua_pushcclosure(L, shapetool_setmarks, 1); lua_setfield(L, -2, "setMarks"); lua_pushlightuserdata(L, tool); lua_pushcclosure(L, shapetool_setsnapping, 1); lua_setfield(L, -2, "setSnapping"); canvas->setTool(tool); return 0; } static int appui_pastetool(lua_State *L) { CanvasBase *canvas = check_canvas(L, 1); Object *obj = check_object(L, 2)->obj; lua_pushvalue(L, 3); int luatool = luaL_ref(L, LUA_REGISTRYINDEX); PasteTool *tool = new PasteTool(canvas, L, luatool, obj->clone()); // add methods to Lua tool lua_rawgeti(L, LUA_REGISTRYINDEX, luatool); lua_pushlightuserdata(L, tool); lua_pushcclosure(L, luatool_setcolor, 1); lua_setfield(L, -2, "setColor"); lua_pushlightuserdata(L, tool); lua_pushcclosure(L, pastetool_setmatrix, 1); lua_setfield(L, -2, "setMatrix"); canvas->setTool(tool); return 0; } // -------------------------------------------------------------------- static int appui_win(lua_State *L) { AppUiBase **ui = check_appui(L, 1); push_winid(L, (*ui)->windowId()); return 1; } static int appui_close(lua_State *L) { AppUiBase **ui = check_appui(L, 1); (*ui)->closeWindow(); return 0; } static int appui_clipboard(lua_State *L) { AppUiBase **ui = check_appui(L, 1); return (*ui)->clipboard(L); } static int appui_setClipboard(lua_State *L) { AppUiBase **ui = check_appui(L, 1); return (*ui)->setClipboard(L); } // This is only used on Windows to compute the shortcuts... static int appui_actionInfo(lua_State *L) { AppUiBase **ui = check_appui(L, 1); return (*ui)->actionInfo(L); } static int appui_actionState(lua_State *L) { AppUiBase **ui = check_appui(L, 1); const char *name = luaL_checklstring(L, 2, nullptr); lua_pushboolean(L, (*ui)->actionState(name)); return 1; } static int appui_setActionState(lua_State *L) { AppUiBase **ui = check_appui(L, 1); const char *name = luaL_checklstring(L, 2, nullptr); bool val = lua_toboolean(L, 3); (*ui)->setActionState(name, val); return 0; } static int appui_setupSymbolicNames(lua_State *L) { AppUiBase **ui = check_appui(L, 1); Cascade *sheets = check_cascade(L, 2)->cascade; (*ui)->setupSymbolicNames(sheets); return 0; } static int appui_setAttributes(lua_State *L) { AppUiBase **ui = check_appui(L, 1); Cascade *sheets = check_cascade(L, 2)->cascade; AllAttributes all; check_allattributes(L, 3, all); (*ui)->setAttributes(all, sheets); return 0; } static int appui_setGridAngleSize(lua_State *L) { AppUiBase **ui = check_appui(L, 1); Attribute gs = check_number_attribute(L, 2); Attribute as = check_number_attribute(L, 3); (*ui)->setGridAngleSize(gs, as); return 0; } static int appui_setLayers(lua_State *L) { AppUiBase **ui = check_appui(L, 1); Page *page = check_page(L, 2)->page; int view = check_viewno(L, 3, page); (*ui)->setLayers(page, view); return 0; } static int appui_setNumbers(lua_State *L) { AppUiBase **ui = check_appui(L, 1); String vno; String pno; if (!lua_isnil(L, 2)) vno = luaL_checklstring(L, 2, nullptr); bool vm = lua_toboolean(L, 3); if (!lua_isnil(L, 4)) pno = luaL_checklstring(L, 4, nullptr); bool pm = lua_toboolean(L, 5); (*ui)->setNumbers(vno, vm, pno, pm); return 0; } static int appui_setBookmarks(lua_State *L) { AppUiBase **ui = check_appui(L, 1); luaL_argcheck(L, lua_istable(L, 2), 2, "argument is not a table"); int no = lua_rawlen(L, 2); std::vector bm; for (int i = 1; i <= no; ++i) { lua_rawgeti(L, 2, i); luaL_argcheck(L, lua_isstring(L, -1), 2, "item is not a string"); bm.push_back(String(lua_tolstring(L, -1, nullptr))); lua_pop(L, 1); } (*ui)->setBookmarks(no, &bm[0]); return 0; } static int appui_setWindowTitle(lua_State *L) { AppUiBase **ui = check_appui(L, 1); bool mod = lua_toboolean(L, 2); const char *s = luaL_checklstring(L, 3, nullptr); (*ui)->setWindowCaption(mod, s); return 0; } static int appui_setNotes(lua_State *L) { AppUiBase **ui = check_appui(L, 1); const char *s = luaL_checklstring(L, 2, nullptr); (*ui)->setNotes(s); return 0; } static int appui_setRecentFiles(lua_State *L) { AppUiBase **ui = check_appui(L, 1); luaL_argcheck(L, lua_istable(L, 2), 2, "argument is not a table"); int no = lua_rawlen(L, 2); std::vector s; for (int i = 1; i <= no; ++i) { lua_rawgeti(L, 2, i); luaL_argcheck(L, lua_isstring(L, -1), 2, "item is not a string"); s.push_back(String(lua_tolstring(L, -1, nullptr))); lua_pop(L, 1); } (*ui)->setRecentFileMenu(s); return 0; } static int appui_showTool(lua_State *L) { static const char * const option_names[] = { "properties", "bookmarks", "notes", "layers", nullptr }; AppUiBase **ui = check_appui(L, 1); int m = luaL_checkoption(L, 2, nullptr, option_names); bool s = lua_toboolean(L, 3); (*ui)->setToolVisible(m, s); return 0; } static int appui_explain(lua_State *L) { AppUiBase **ui = check_appui(L, 1); const char *s = luaL_checklstring(L, 2, nullptr); int t = 4000; if (lua_isnumber(L, 3)) t = lua_tointegerx(L, 3, nullptr); (*ui)->explain(s, t); return 0; } // -------------------------------------------------------------------- void get_page_sorter_size(lua_State *L, int &width, int &height, int &thumbWidth) { thumbWidth = 300; width = 600; height = 480; lua_getglobal(L, "prefs"); lua_getfield(L, -1, "page_sorter_size"); if (lua_istable(L, -1)) { lua_rawgeti(L, -1, 1); if (lua_isnumber(L, -1)) width = lua_tointegerx(L, -1, nullptr); lua_rawgeti(L, -2, 2); if (lua_isnumber(L, -1)) height = lua_tointegerx(L, -1, nullptr); lua_pop(L, 2); } lua_pop(L, 1); // page_sorter_size lua_getfield(L, -1, "thumbnail_width"); if (lua_isnumber(L, -1)) thumbWidth = lua_tointegerx(L, -1, nullptr); lua_pop(L, 1); // thumbnail_width, prefs } static int appui_selectPage(lua_State *L) { check_appui(L, 1); // not actually used now Document **doc = check_document(L, 2); int page = -1; if (lua_isnumber(L, 3)) { page = lua_tointegerx(L, 3, nullptr); luaL_argcheck(L, 1 <= page && page <= (*doc)->countPages(), 3, "invalid page number"); } int startIndex = 1; if (lua_isnumber(L, 4)) { startIndex = lua_tointegerx(L, 4, nullptr); int maxIndex = (page < 0) ? (*doc)->countPages() : (*doc)->page(page-1)->countViews(); luaL_argcheck(L, 1 <= startIndex && startIndex <= maxIndex, 4, "invalid start index"); } int width, height, thumbWidth; get_page_sorter_size(L, width, height, thumbWidth); int sel = CanvasBase::selectPageOrView(*doc, page - 1, startIndex - 1, thumbWidth, width, height); if (sel >= 0) { lua_pushinteger(L, sel + 1); return 1; } else return 0; } static int appui_pageSorter(lua_State *L) { AppUiBase **ui = check_appui(L, 1); Document **doc = check_document(L, 2); int page = -1; if (lua_isnumber(L, 3)) { page = lua_tointegerx(L, 3, nullptr); luaL_argcheck(L, 1 <= page && page <= (*doc)->countPages(), 3, "invalid page number"); } int width, height, thumbWidth; get_page_sorter_size(L, width, height, thumbWidth); return (*ui)->pageSorter(L, *doc, page - 1, width, height, thumbWidth); } static const char *const render_formats[] = {"svg", "png", "eps", "pdf", nullptr }; static int appui_renderPage(lua_State *L) { // AppUiBase **ui = check_appui(L, 1); // not used Document **doc = check_document(L, 2); int pageno = luaL_checkinteger(L, 3); int viewno = luaL_checkinteger(L, 4); Thumbnail::TargetFormat fm = Thumbnail::TargetFormat(luaL_checkoption(L, 5, nullptr, render_formats)); const char *dst = luaL_checklstring(L, 6, nullptr); double zoom = luaL_checknumber(L, 7); Thumbnail tn(*doc, 0); tn.setTransparent(lua_toboolean(L, 8)); tn.setNoCrop(lua_toboolean(L, 9)); const Page *page = (*doc)->page(pageno - 1); tn.saveRender(fm, dst, page, viewno - 1, zoom); return 0; } // -------------------------------------------------------------------- static const struct luaL_Reg appui_methods[] = { { "__tostring", appui_tostring }, { "__gc", appui_destructor }, // -------------------------------------------------------------------- { "setPage", appui_setPage}, { "pan", appui_pan}, { "setPan", appui_setPan}, { "zoom", appui_zoom}, { "setZoom", appui_setZoom}, { "setResources", appui_setResources}, { "pos", appui_pos}, { "globalPos", appui_globalPos}, { "unsnappedPos", appui_unsnappedPos}, { "simpleSnapPos", appui_simpleSnapPos }, { "setFifiVisible", appui_setFifiVisible}, { "setInkMode", appui_setInkMode }, { "setSelectionVisible", appui_setSelectionVisible}, { "setSnap", appui_setSnap}, { "setSnapIndicator", appui_setSnapIndicator}, { "setAutoOrigin", appui_setAutoOrigin }, { "update", appui_update}, { "finishTool", appui_finishTool}, { "canvasSize", appui_canvasSize }, { "setCursor", appui_setCursor }, { "setNumbering", appui_setNumbering }, { "setPretty", appui_setPretty }, { "setScreen", appui_setScreen }, { "type3Font", appui_type3Font }, // -------------------------------------------------------------------- { "panTool", appui_pantool }, { "selectTool", appui_selecttool }, { "transformTool", appui_transformtool }, { "shapeTool", appui_shapetool }, { "pasteTool", appui_pastetool }, // -------------------------------------------------------------------- { "win", appui_win}, { "close", appui_close}, { "setClipboard", appui_setClipboard }, { "clipboard", appui_clipboard }, { "setActionState", appui_setActionState }, { "actionState", appui_actionState }, { "actionInfo", appui_actionInfo }, { "explain", appui_explain }, { "setWindowTitle", appui_setWindowTitle }, { "setupSymbolicNames", appui_setupSymbolicNames }, { "setAttributes", appui_setAttributes }, { "setGridAngleSize", appui_setGridAngleSize }, { "setLayers", appui_setLayers }, { "setNumbers", appui_setNumbers }, { "setBookmarks", appui_setBookmarks }, { "setNotes", appui_setNotes }, { "setRecentFiles", appui_setRecentFiles }, { "showTool", appui_showTool }, { "selectPage", appui_selectPage }, { "pageSorter", appui_pageSorter }, { "renderPage", appui_renderPage }, { nullptr, nullptr } }; // -------------------------------------------------------------------- static int appui_constructor(lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); // this is the model AppUiBase **ui = (AppUiBase **) lua_newuserdata(L, sizeof(AppUiBase *)); *ui = nullptr; luaL_getmetatable(L, "Ipe.appui"); lua_setmetatable(L, -2); lua_pushvalue(L, 1); int model = luaL_ref(L, LUA_REGISTRYINDEX); *ui = createAppUi(L, model); CanvasBase::Style style; style.pretty = false; style.paperColor = Color(1000,1000,1000); style.primarySelectionColor = Color(1000,0,0); style.secondarySelectionColor = Color(1000,0,1000); style.classicGrid = false; style.thinLine = 0.2; style.thickLine = 0.9; style.thinStep = 1; style.thickStep = 4; style.paperClip = false; style.numberPages = false; lua_getglobal(L, "prefs"); lua_getfield(L, -1, "canvas_style"); if (!lua_isnil(L, -1)) { lua_getfield(L, -1, "paper_color"); if (!lua_isnil(L, -1)) style.paperColor = check_color(L, lua_gettop(L)); lua_pop(L, 1); // paper_color lua_getfield(L, -1, "primary_color"); if (!lua_isnil(L, -1)) style.primarySelectionColor = check_color(L, lua_gettop(L)); lua_pop(L, 1); // primary_color lua_getfield(L, -1, "secondary_color"); if (!lua_isnil(L, -1)) style.secondarySelectionColor = check_color(L, lua_gettop(L)); lua_pop(L, 1); // secondary_color lua_getfield(L, -1, "classic_grid"); style.classicGrid = lua_toboolean(L, -1); lua_pop(L, 1); // classic_grid lua_getfield(L, -1, "thin_grid_line"); if (lua_isnumber(L, -1)) style.thinLine = lua_tonumberx(L, -1, nullptr); lua_pop(L, 1); // thin_grid_line lua_getfield(L, -1, "thick_grid_line"); if (lua_isnumber(L, -1)) style.thickLine = lua_tonumberx(L, -1, nullptr); lua_pop(L, 1); // thick_grid_line lua_getfield(L, -1, "thin_step"); if (lua_isnumber(L, -1)) style.thinStep = lua_tointegerx(L, -1, nullptr); lua_pop(L, 1); // thin_step lua_getfield(L, -1, "thick_step"); if (lua_isnumber(L, -1)) style.thickStep = lua_tointegerx(L, -1, nullptr); lua_pop(L, 1); // thick_step } lua_pop(L, 1); // canvas_style int width = -1, height = -1, x = -1, y = -1; lua_getfield(L, -1, "window_size"); if (lua_istable(L, -1)) { lua_rawgeti(L, -1, 1); if (lua_isnumber(L, -1)) width = lua_tointegerx(L, -1, nullptr); lua_rawgeti(L, -2, 2); if (lua_isnumber(L, -1)) height = lua_tointegerx(L, -1, nullptr); lua_rawgeti(L, -3, 3); if (lua_isnumber(L, -1)) x = lua_tointegerx(L, -1, nullptr); lua_rawgeti(L, -4, 4); if (lua_isnumber(L, -1)) y = lua_tointegerx(L, -1, nullptr); lua_pop(L, 4); } lua_pop(L, 1); // window_size lua_pop(L, 1); // prefs (*ui)->canvas()->setCanvasStyle(style); (*ui)->showWindow(width, height, x, y); return 1; } // -------------------------------------------------------------------- int luaopen_appui(lua_State *L) { lua_pushcfunction(L, appui_constructor); lua_setglobal(L, "AppUi"); make_metatable(L, "Ipe.appui", appui_methods); return 0; } // --------------------------------------------------------------------