[lua] Add new GraphicsContext type for Canvas onpaint event

We include a simple initial API for the GraphicsContext (like
stroking/filling rectangles and images).
This commit is contained in:
David Capello 2022-12-14 17:04:50 -03:00
parent 6e13e59aff
commit 2cb526a19b
9 changed files with 283 additions and 7 deletions

View File

@ -175,6 +175,7 @@ if(ENABLE_SCRIPTING)
script/events_class.cpp
script/frame_class.cpp
script/frames_class.cpp
script/graphics_context.cpp
script/grid_class.cpp
script/image_class.cpp
script/image_iterator_class.cpp

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2020-2022 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -37,6 +37,14 @@ gfx::Color color_utils::blackandwhite_neg(gfx::Color color)
return gfx::rgba(0, 0, 0);
}
app::Color color_utils::color_from_ui(const gfx::Color color)
{
return app::Color::fromRgb(gfx::getr(color),
gfx::getg(color),
gfx::getb(color),
gfx::geta(color));
}
gfx::Color color_utils::color_for_ui(const app::Color& color)
{
gfx::Color c = gfx::ColorNone;

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2020-2022 Igara Studio S.A.
// Copyright (C) 2001-2015 David Capello
//
// This program is distributed under the terms of
@ -25,6 +25,7 @@ namespace app {
gfx::Color blackandwhite(gfx::Color color);
gfx::Color blackandwhite_neg(gfx::Color color);
app::Color color_from_ui(const gfx::Color color);
gfx::Color color_for_ui(const app::Color& color);
doc::color_t color_for_image(const app::Color& color, doc::PixelFormat format);
doc::color_t color_for_image_without_alpha(const app::Color& color, doc::PixelFormat format);

View File

@ -6,6 +6,7 @@
#include "app/script/canvas_widget.h"
#include "app/script/graphics_context.h"
#include "app/ui/skin/skin_theme.h"
#include "os/system.h"
#include "ui/message.h"
@ -58,6 +59,10 @@ void Canvas::onResize(ui::ResizeEvent& ev)
os::Paint p;
p.color(bgColor());
m_surface->drawRect(m_surface->bounds(), p);
// Draw only on resize (onPaint we draw the cached m_surface)
GraphicsContext gc(m_surface);
Paint(gc);
}
}
else
@ -66,8 +71,6 @@ void Canvas::onResize(ui::ResizeEvent& ev)
void Canvas::onPaint(ui::PaintEvent& ev)
{
Paint(ev);
auto g = ev.graphics();
const gfx::Rect rc = clientBounds();
if (m_surface)

View File

@ -14,6 +14,8 @@
namespace app {
namespace script {
class GraphicsContext;
// 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 {
@ -22,7 +24,7 @@ public:
Canvas();
obs::signal<void(ui::PaintEvent&)> Paint;
obs::signal<void(GraphicsContext&)> Paint;
private:
void onInitTheme(ui::InitThemeEvent& ev) override;

View File

@ -15,6 +15,7 @@
#include "app/file_selector.h"
#include "app/script/canvas_widget.h"
#include "app/script/engine.h"
#include "app/script/graphics_context.h"
#include "app/script/luacpp.h"
#include "app/ui/color_button.h"
#include "app/ui/color_shades.h"
@ -915,8 +916,9 @@ int Dialog_canvas(lua_State* L)
if (type == LUA_TFUNCTION) {
Dialog_connect_signal(
L, 1, widget->Paint,
[](lua_State* L, ui::PaintEvent& ev) {
// TODO
[](lua_State* L, GraphicsContext& gc) {
push_new<GraphicsContext>(L, std::move(gc));
lua_setfield(L, -2, "context");
});
}
lua_pop(L, 1);

View File

@ -159,6 +159,7 @@ void register_color_class(lua_State* L);
void register_color_space_class(lua_State* L);
#ifdef ENABLE_UI
void register_dialog_class(lua_State* L);
void register_graphics_context_class(lua_State* L);
#endif
void register_events_class(lua_State* L);
void register_frame_class(lua_State* L);
@ -412,6 +413,7 @@ Engine::Engine()
register_color_space_class(L);
#ifdef ENABLE_UI
register_dialog_class(L);
register_graphics_context_class(L);
#endif
register_events_class(L);
register_frame_class(L);

View File

@ -0,0 +1,177 @@
// Aseprite
// Copyright (C) 2022 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/script/graphics_context.h"
#include "app/color.h"
#include "app/color_utils.h"
#include "app/modules/palettes.h"
#include "app/script/engine.h"
#include "app/script/luacpp.h"
#include "app/util/conversion_to_surface.h"
#ifdef ENABLE_UI
namespace app {
namespace script {
void GraphicsContext::drawImage(const doc::Image* img, int x, int y)
{
convert_image_to_surface(
img,
get_current_palette(),
m_surface.get(),
0, 0,
x, y,
img->width(), img->height());
}
namespace {
int GraphicsContext_gc(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
gc->~GraphicsContext();
return 0;
}
int GraphicsContext_save(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
gc->save();
return 0;
}
int GraphicsContext_restore(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
gc->restore();
return 0;
}
int GraphicsContext_strokeRect(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
const gfx::Rect rc = convert_args_into_rect(L, 2);
gc->strokeRect(rc);
return 0;
}
int GraphicsContext_fillRect(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
const gfx::Rect rc = convert_args_into_rect(L, 2);
gc->fillRect(rc);
return 0;
}
int GraphicsContext_drawImage(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
if (const doc::Image* img = may_get_image_from_arg(L, 2)) {
int x = lua_tointeger(L, 3);
int y = lua_tointeger(L, 4);
gc->drawImage(img, x, y);
}
return 0;
}
int GraphicsContext_get_width(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
lua_pushinteger(L, gc->width());
return 1;
}
int GraphicsContext_get_height(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
lua_pushinteger(L, gc->height());
return 1;
}
int GraphicsContext_get_antialias(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
lua_pushboolean(L, gc->antialias());
return 1;
}
int GraphicsContext_set_antialias(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
const bool antialias = lua_toboolean(L, 2);
gc->antialias(antialias);
return 1;
}
int GraphicsContext_get_color(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
push_obj(L, color_utils::color_from_ui(gc->color()));
return 1;
}
int GraphicsContext_set_color(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
const app::Color color = convert_args_into_color(L, 2);
gc->color(color_utils::color_for_ui(color));
return 1;
}
int GraphicsContext_get_strokeWidth(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
lua_pushnumber(L, gc->strokeWidth());
return 1;
}
int GraphicsContext_set_strokeWidth(lua_State* L)
{
auto gc = get_obj<GraphicsContext>(L, 1);
const float strokeWidth = lua_tonumber(L, 2);
gc->strokeWidth(strokeWidth);
return 1;
}
const luaL_Reg GraphicsContext_methods[] = {
{ "__gc", GraphicsContext_gc },
{ "save", GraphicsContext_save },
{ "restore", GraphicsContext_restore },
{ "strokeRect", GraphicsContext_strokeRect },
{ "fillRect", GraphicsContext_fillRect },
{ "drawImage", GraphicsContext_drawImage },
{ nullptr, nullptr }
};
const Property GraphicsContext_properties[] = {
{ "width", GraphicsContext_get_width, nullptr },
{ "height", GraphicsContext_get_height, nullptr },
{ "antialias", GraphicsContext_get_antialias, GraphicsContext_set_antialias },
{ "color", GraphicsContext_get_color, GraphicsContext_set_color },
{ "strokeWidth", GraphicsContext_get_strokeWidth, GraphicsContext_set_strokeWidth },
{ nullptr, nullptr, nullptr }
};
} // anonymous namespace
DEF_MTNAME(GraphicsContext);
void register_graphics_context_class(lua_State* L)
{
REG_CLASS(L, GraphicsContext);
REG_CLASS_PROPERTIES(L, GraphicsContext);
}
} // namespace script
} // namespace app
#endif // ENABLE_UI

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.
#ifndef APP_SCRIPT_GRAPHICS_CONTEXT_H_INCLUDED
#define APP_SCRIPT_GRAPHICS_CONTEXT_H_INCLUDED
#pragma once
#ifdef ENABLE_UI
#include "os/paint.h"
#include "os/surface.h"
#include <stack>
namespace doc {
class Image;
}
namespace app {
namespace script {
class GraphicsContext {
public:
GraphicsContext(const os::SurfaceRef& surface) : m_surface(surface) { }
GraphicsContext(GraphicsContext&& gc) {
std::swap(m_surface, gc.m_surface);
}
int width() const { return m_surface->width(); }
int height() const { return m_surface->height(); }
void save() {
m_saved.push(m_paint);
m_surface->save();
}
void restore() {
if (!m_saved.empty()) {
m_paint = m_saved.top();
m_saved.pop();
m_surface->restore();
}
}
void strokeRect(const gfx::Rect& rc) {
m_paint.style(os::Paint::Stroke);
m_surface->drawRect(rc, m_paint);
}
void fillRect(const gfx::Rect& rc) {
m_paint.style(os::Paint::Fill);
m_surface->drawRect(rc, m_paint);
}
bool antialias() const { return m_paint.antialias(); }
void antialias(bool value) { m_paint.antialias(value); }
gfx::Color color() const { return m_paint.color(); }
void color(gfx::Color color) { m_paint.color(color); }
float strokeWidth() const { return m_paint.strokeWidth(); }
void strokeWidth(float value) { m_paint.strokeWidth(value); }
void drawImage(const doc::Image* img, int x, int y);
private:
os::SurfaceRef m_surface = nullptr;
os::Paint m_paint;
std::stack<os::Paint> m_saved;
};
} // namespace script
} // namespace app
#endif
#endif