[lua] Add initial version Dialog:canvas() (aseprite/api#87)

Right now it just creates a plain widget, but now we can specify
hexpand/vexpand arguments too so we can create a canvas with a fixed
size or with dynamic size (e.g. to use the whole dialog client area).

The onpaint event is not functional yet.
This commit is contained in:
David Capello 2022-12-14 12:27:24 -03:00
parent 3c77928a6f
commit 6e13e59aff
4 changed files with 176 additions and 2 deletions

View File

@ -165,6 +165,7 @@ if(ENABLE_SCRIPTING)
script/app_fs_object.cpp
script/app_object.cpp
script/brush_class.cpp
script/canvas_widget.cpp
script/cel_class.cpp
script/cels_class.cpp
script/color_class.cpp

View File

@ -0,0 +1,80 @@
// Aseprite
// Copyright (c) 2022 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#include "app/script/canvas_widget.h"
#include "app/ui/skin/skin_theme.h"
#include "os/system.h"
#include "ui/message.h"
#include "ui/paint_event.h"
#include "ui/resize_event.h"
#include "ui/size_hint_event.h"
#ifdef ENABLE_UI
namespace app {
namespace script {
// static
ui::WidgetType Canvas::Type()
{
static ui::WidgetType type = ui::kGenericWidget;
if (type == ui::kGenericWidget)
type = ui::register_widget_type();
return type;
}
Canvas::Canvas() : ui::Widget(Type())
{
}
void Canvas::onInitTheme(ui::InitThemeEvent& ev)
{
Widget::onInitTheme(ev);
gfx::Color bg;
if (auto theme = skin::SkinTheme::get(this))
bg = theme->colors.windowFace();
else
bg = gfx::rgba(0, 0, 0);
setBgColor(bg);
}
void Canvas::onResize(ui::ResizeEvent& ev)
{
Widget::onResize(ev);
if (os::instance() && !ev.bounds().isEmpty()) {
const int w = ev.bounds().w;
const int h = ev.bounds().h;
if (!m_surface ||
m_surface->width() != w ||
m_surface->height() != h) {
m_surface = os::instance()->makeSurface(w, h);
os::Paint p;
p.color(bgColor());
m_surface->drawRect(m_surface->bounds(), p);
}
}
else
m_surface.reset();
}
void Canvas::onPaint(ui::PaintEvent& ev)
{
Paint(ev);
auto g = ev.graphics();
const gfx::Rect rc = clientBounds();
if (m_surface)
g->drawSurface(m_surface.get(), rc.x, rc.y);
}
} // namespace script
} // namespace app
#endif // ENABLE_UI

View File

@ -0,0 +1,38 @@
// Aseprite
// Copyright (c) 2022 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_SCRIPT_CANVAS_H_INCLUDED
#define APP_SCRIPT_CANVAS_H_INCLUDED
#pragma once
#include "os/surface.h"
#include "ui/widget.h"
namespace app {
namespace script {
// The canvas widget of a Dialog() created with Dialog:canvas{ ... }
// This is a generic widget where all its events can be listened.
class Canvas : public ui::Widget {
public:
static ui::WidgetType Type();
Canvas();
obs::signal<void(ui::PaintEvent&)> Paint;
private:
void onInitTheme(ui::InitThemeEvent& ev) override;
void onResize(ui::ResizeEvent& ev) override;
void onPaint(ui::PaintEvent& ev) override;
os::SurfaceRef m_surface;
};
} // namespace script
} // namespace app
#endif

View File

@ -13,6 +13,7 @@
#include "app/color.h"
#include "app/color_utils.h"
#include "app/file_selector.h"
#include "app/script/canvas_widget.h"
#include "app/script/engine.h"
#include "app/script/luacpp.h"
#include "app/ui/color_button.h"
@ -334,6 +335,9 @@ int Dialog_add_widget(lua_State* L, Widget* widget)
const char* label = nullptr;
std::string id;
bool visible = true;
bool hexpand = true;
// Canvas is vertically expansive by default too
bool vexpand = (widget->type() == Canvas::Type());
// This is to separate different kind of widgets without label in
// different rows.
@ -380,6 +384,15 @@ int Dialog_add_widget(lua_State* L, Widget* widget)
widget->setVisible(visible);
}
lua_pop(L, 1);
// Expand horizontally/vertically, it allows to indicate that a
// specific widget is not expansive (e.g. a canvas with a fixed
// size)
type = lua_getfield(L, 2, "hexpand");
type = lua_getfield(L, 2, "vexpand");
if (type != LUA_TNIL) hexpand = lua_toboolean(L, -2);
if (type != LUA_TNIL) vexpand = lua_toboolean(L, -1);
lua_pop(L, 2);
}
if (label || !dlg->hbox) {
@ -398,11 +411,15 @@ int Dialog_add_widget(lua_State* L, Widget* widget)
auto hbox = new ui::HBox;
if (widget->type() == ui::kButtonWidget)
hbox->enableFlags(ui::HOMOGENEOUS);
dlg->grid.addChildInCell(hbox, 1, 1, ui::HORIZONTAL | ui::TOP);
dlg->grid.addChildInCell(
hbox, 1, 1,
ui::HORIZONTAL | (vexpand ? ui::VERTICAL: ui::TOP));
dlg->hbox = hbox;
}
widget->setExpansive(true);
widget->setExpansive(hexpand);
dlg->hbox->addChild(widget);
lua_pushvalue(L, 1);
@ -872,6 +889,43 @@ int Dialog_file(lua_State* L)
return Dialog_add_widget(L, widget);
}
int Dialog_canvas(lua_State* L)
{
auto widget = new Canvas;
if (lua_istable(L, 2)) {
gfx::Size sz(0, 0);
int type = lua_getfield(L, 2, "width");
if (type != LUA_TNIL) {
sz.w = lua_tointegerx(L, -1, nullptr);
}
lua_pop(L, 1);
type = lua_getfield(L, 2, "height");
if (type != LUA_TNIL) {
sz.h = lua_tointegerx(L, -1, nullptr);
}
lua_pop(L, 1);
widget->setSizeHint(sz);
if (lua_istable(L, 2)) {
int type = lua_getfield(L, 2, "onpaint");
if (type == LUA_TFUNCTION) {
Dialog_connect_signal(
L, 1, widget->Paint,
[](lua_State* L, ui::PaintEvent& ev) {
// TODO
});
}
lua_pop(L, 1);
}
}
return Dialog_add_widget(L, widget);
}
int Dialog_modify(lua_State* L)
{
auto dlg = get_obj<Dialog>(L, 1);
@ -1275,6 +1329,7 @@ const luaL_Reg Dialog_methods[] = {
{ "color", Dialog_color },
{ "shades", Dialog_shades },
{ "file", Dialog_file },
{ "canvas", Dialog_canvas },
{ "modify", Dialog_modify },
{ nullptr, nullptr }
};