mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-03 21:46:20 +00:00
Merge branch 'canvas' (fix aseprite/api#87)
This commit is contained in:
commit
5a5ac179cd
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit ad742295fb92edaa9c51c7cf8c68fe1e7d550357
|
||||
Subproject commit 817e0c5b1c27f974f0fc298c96bb89f144d5715e
|
@ -164,7 +164,9 @@ if(ENABLE_SCRIPTING)
|
||||
script/app_command_object.cpp
|
||||
script/app_fs_object.cpp
|
||||
script/app_object.cpp
|
||||
script/app_theme_object.cpp
|
||||
script/brush_class.cpp
|
||||
script/canvas_widget.cpp
|
||||
script/cel_class.cpp
|
||||
script/cels_class.cpp
|
||||
script/color_class.cpp
|
||||
@ -174,6 +176,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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -480,6 +480,12 @@ int App_get_events(lua_State* L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int App_get_theme(lua_State* L)
|
||||
{
|
||||
push_app_theme(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int App_get_activeSprite(lua_State* L)
|
||||
{
|
||||
app::Context* ctx = App::instance()->context();
|
||||
@ -761,6 +767,7 @@ const Property App_properties[] = {
|
||||
{ "isUIAvailable", App_get_isUIAvailable, nullptr },
|
||||
{ "defaultPalette", App_get_defaultPalette, App_set_defaultPalette },
|
||||
{ "events", App_get_events, nullptr },
|
||||
{ "theme", App_get_theme, nullptr },
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
|
107
src/app/script/app_theme_object.cpp
Normal file
107
src/app/script/app_theme_object.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
// 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/color.h"
|
||||
#include "app/color_utils.h"
|
||||
#include "app/script/luacpp.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
namespace {
|
||||
|
||||
struct Theme { };
|
||||
struct ThemeDimension { };
|
||||
struct ThemeColor { };
|
||||
|
||||
int ThemeDimension_index(lua_State* L)
|
||||
{
|
||||
const char* id = lua_tostring(L, 2);
|
||||
if (!id)
|
||||
return luaL_error(L, "id in app.theme.dimension.id must be a string");
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
const int value = skin::SkinTheme::instance()->getDimensionById(id);
|
||||
lua_pushinteger(L, value);
|
||||
#else
|
||||
lua_pushinteger(L, 0);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ThemeColor_index(lua_State* L)
|
||||
{
|
||||
const char* id = lua_tostring(L, 2);
|
||||
if (!id)
|
||||
return luaL_error(L, "id in app.theme.color.id must be a string");
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
const gfx::Color uiColor = skin::SkinTheme::instance()->getColorById(id);
|
||||
push_obj<app::Color>(L, color_utils::color_from_ui(uiColor));
|
||||
#else
|
||||
push_obj<app::Color>(L, app::Color::fromMask());
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Theme_get_dimension(lua_State* L)
|
||||
{
|
||||
push_obj<ThemeDimension>(L, ThemeDimension());
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Theme_get_color(lua_State* L)
|
||||
{
|
||||
push_obj<ThemeColor>(L, ThemeColor());
|
||||
return 1;
|
||||
}
|
||||
|
||||
const luaL_Reg Theme_methods[] = {
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const Property Theme_properties[] = {
|
||||
{ "dimension", Theme_get_dimension, nullptr },
|
||||
{ "color", Theme_get_color, nullptr },
|
||||
{ nullptr, nullptr, nullptr }
|
||||
};
|
||||
|
||||
const luaL_Reg ThemeDimension_methods[] = {
|
||||
{ "__index", ThemeDimension_index },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
const luaL_Reg ThemeColor_methods[] = {
|
||||
{ "__index", ThemeColor_index },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
DEF_MTNAME(Theme);
|
||||
DEF_MTNAME(ThemeDimension);
|
||||
DEF_MTNAME(ThemeColor);
|
||||
|
||||
void register_theme_classes(lua_State* L)
|
||||
{
|
||||
REG_CLASS(L, Theme);
|
||||
REG_CLASS(L, ThemeDimension);
|
||||
REG_CLASS(L, ThemeColor);
|
||||
REG_CLASS_PROPERTIES(L, Theme);
|
||||
}
|
||||
|
||||
void push_app_theme(lua_State* L)
|
||||
{
|
||||
push_obj<Theme>(L, Theme());
|
||||
}
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
118
src/app/script/canvas_widget.cpp
Normal file
118
src/app/script/canvas_widget.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
// 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/script/graphics_context.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::callPaint()
|
||||
{
|
||||
if (!m_surface)
|
||||
return;
|
||||
|
||||
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);
|
||||
gc.font(AddRef(font()));
|
||||
Paint(gc);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool Canvas::onProcessMessage(ui::Message* msg)
|
||||
{
|
||||
switch (msg->type()) {
|
||||
|
||||
case ui::kMouseMoveMessage: {
|
||||
auto mouseMsg = static_cast<ui::MouseMessage*>(msg);
|
||||
MouseMove(mouseMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
case ui::kMouseDownMessage: {
|
||||
auto mouseMsg = static_cast<ui::MouseMessage*>(msg);
|
||||
MouseDown(mouseMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
case ui::kMouseUpMessage: {
|
||||
auto mouseMsg = static_cast<ui::MouseMessage*>(msg);
|
||||
MouseUp(mouseMsg);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return ui::Widget::onProcessMessage(msg);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
callPaint();
|
||||
}
|
||||
}
|
||||
else
|
||||
m_surface.reset();
|
||||
}
|
||||
|
||||
void Canvas::onPaint(ui::PaintEvent& 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
|
46
src/app/script/canvas_widget.h
Normal file
46
src/app/script/canvas_widget.h
Normal file
@ -0,0 +1,46 @@
|
||||
// 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 {
|
||||
|
||||
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 {
|
||||
public:
|
||||
static ui::WidgetType Type();
|
||||
|
||||
Canvas();
|
||||
|
||||
void callPaint();
|
||||
|
||||
obs::signal<void(GraphicsContext&)> Paint;
|
||||
obs::signal<void(ui::MouseMessage*)> MouseMove;
|
||||
obs::signal<void(ui::MouseMessage*)> MouseDown;
|
||||
obs::signal<void(ui::MouseMessage*)> MouseUp;
|
||||
|
||||
private:
|
||||
void onInitTheme(ui::InitThemeEvent& ev) override;
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
void onResize(ui::ResizeEvent& ev) override;
|
||||
void onPaint(ui::PaintEvent& ev) override;
|
||||
|
||||
os::SurfaceRef m_surface;
|
||||
};
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -13,7 +13,9 @@
|
||||
#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/graphics_context.h"
|
||||
#include "app/script/luacpp.h"
|
||||
#include "app/ui/color_button.h"
|
||||
#include "app/ui/color_shades.h"
|
||||
@ -30,11 +32,13 @@
|
||||
#include "ui/grid.h"
|
||||
#include "ui/label.h"
|
||||
#include "ui/manager.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/separator.h"
|
||||
#include "ui/slider.h"
|
||||
#include "ui/window.h"
|
||||
|
||||
#include <map>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -334,6 +338,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 +387,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 +414,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 +892,78 @@ 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, GraphicsContext& gc) {
|
||||
push_new<GraphicsContext>(L, std::move(gc));
|
||||
lua_setfield(L, -2, "context");
|
||||
});
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
auto mouseCallback =
|
||||
[](lua_State* L, ui::MouseMessage* msg) {
|
||||
ASSERT(msg->recipient());
|
||||
if (!msg->recipient())
|
||||
return;
|
||||
|
||||
lua_pushinteger(L, msg->position().x - msg->recipient()->bounds().x);
|
||||
lua_setfield(L, -2, "x");
|
||||
|
||||
lua_pushinteger(L, msg->position().y - msg->recipient()->bounds().y);
|
||||
lua_setfield(L, -2, "y");
|
||||
|
||||
lua_pushinteger(L, int(msg->button()));
|
||||
lua_setfield(L, -2, "button");
|
||||
};
|
||||
|
||||
type = lua_getfield(L, 2, "onmousemove");
|
||||
if (type == LUA_TFUNCTION) {
|
||||
Dialog_connect_signal(L, 1, widget->MouseMove, mouseCallback);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
type = lua_getfield(L, 2, "onmousedown");
|
||||
if (type == LUA_TFUNCTION) {
|
||||
Dialog_connect_signal(L, 1, widget->MouseDown, mouseCallback);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
|
||||
type = lua_getfield(L, 2, "onmouseup");
|
||||
if (type == LUA_TFUNCTION) {
|
||||
Dialog_connect_signal(L, 1, widget->MouseUp, mouseCallback);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return Dialog_add_widget(L, widget);
|
||||
}
|
||||
|
||||
int Dialog_modify(lua_State* L)
|
||||
{
|
||||
auto dlg = get_obj<Dialog>(L, 1);
|
||||
@ -1059,6 +1151,27 @@ int Dialog_modify(lua_State* L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Dialog_repaint(lua_State* L)
|
||||
{
|
||||
auto dlg = get_obj<Dialog>(L, 1);
|
||||
std::stack<ui::Widget*> widgets;
|
||||
widgets.push(&dlg->grid);
|
||||
|
||||
while (!widgets.empty()) {
|
||||
auto child = widgets.top();
|
||||
widgets.pop();
|
||||
|
||||
if (child->type() == Canvas::Type()) {
|
||||
static_cast<Canvas*>(child)->callPaint();
|
||||
child->invalidate();
|
||||
}
|
||||
|
||||
for (auto subchild : child->children())
|
||||
widgets.push(subchild);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Dialog_get_data(lua_State* L)
|
||||
{
|
||||
auto dlg = get_obj<Dialog>(L, 1);
|
||||
@ -1275,7 +1388,9 @@ const luaL_Reg Dialog_methods[] = {
|
||||
{ "color", Dialog_color },
|
||||
{ "shades", Dialog_shades },
|
||||
{ "file", Dialog_file },
|
||||
{ "canvas", Dialog_canvas },
|
||||
{ "modify", Dialog_modify },
|
||||
{ "repaint", Dialog_repaint },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
@ -185,6 +186,7 @@ void register_sprite_class(lua_State* L);
|
||||
void register_sprites_class(lua_State* L);
|
||||
void register_tag_class(lua_State* L);
|
||||
void register_tags_class(lua_State* L);
|
||||
void register_theme_classes(lua_State* L);
|
||||
void register_tileset_class(lua_State* L);
|
||||
void register_tilesets_class(lua_State* L);
|
||||
void register_tool_class(lua_State* L);
|
||||
@ -412,6 +414,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);
|
||||
@ -438,6 +441,7 @@ Engine::Engine()
|
||||
register_sprites_class(L);
|
||||
register_tag_class(L);
|
||||
register_tags_class(L);
|
||||
register_theme_classes(L);
|
||||
register_tileset_class(L);
|
||||
register_tilesets_class(L);
|
||||
register_tool_class(L);
|
||||
|
@ -135,6 +135,7 @@ namespace app {
|
||||
};
|
||||
|
||||
void push_app_events(lua_State* L);
|
||||
void push_app_theme(lua_State* L);
|
||||
int push_image_iterator_function(lua_State* L, const doc::Image* image, int extraArgIndex);
|
||||
void push_brush(lua_State* L, const doc::BrushRef& brush);
|
||||
void push_cel_image(lua_State* L, doc::Cel* cel);
|
||||
|
341
src/app/script/graphics_context.cpp
Normal file
341
src/app/script/graphics_context.cpp
Normal file
@ -0,0 +1,341 @@
|
||||
// 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/ui/skin/skin_theme.h"
|
||||
#include "app/util/conversion_to_surface.h"
|
||||
#include "os/draw_text.h"
|
||||
|
||||
#ifdef ENABLE_UI
|
||||
|
||||
namespace app {
|
||||
namespace script {
|
||||
|
||||
void GraphicsContext::fillText(const std::string& text, int x, int y)
|
||||
{
|
||||
os::draw_text(m_surface.get(), m_font.get(),
|
||||
text, m_paint.color(), 0, x, y, nullptr);
|
||||
}
|
||||
|
||||
gfx::Size GraphicsContext::measureText(const std::string& text) const
|
||||
{
|
||||
return os::draw_text(nullptr, m_font.get(), text,
|
||||
0, 0, 0, 0, nullptr).size();
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
void GraphicsContext::drawThemeImage(const std::string& partId, const gfx::Point& pt)
|
||||
{
|
||||
if (auto theme = skin::SkinTheme::instance()) {
|
||||
skin::SkinPartPtr part = theme->getPartById(partId);
|
||||
if (part && part->bitmap(0))
|
||||
m_surface->drawRgbaSurface(part->bitmap(0), pt.x, pt.y);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsContext::drawThemeRect(const std::string& partId, const gfx::Rect& rc)
|
||||
{
|
||||
if (auto theme = skin::SkinTheme::instance()) {
|
||||
skin::SkinPartPtr part = theme->getPartById(partId);
|
||||
if (part && part->bitmap(0)) {
|
||||
ui::Graphics g(nullptr, m_surface, 0, 0);
|
||||
theme->drawRect(&g, rc, part.get(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphicsContext::stroke()
|
||||
{
|
||||
m_paint.style(os::Paint::Stroke);
|
||||
m_surface->drawPath(m_path, m_paint);
|
||||
}
|
||||
|
||||
void GraphicsContext::fill()
|
||||
{
|
||||
m_paint.style(os::Paint::Fill);
|
||||
m_surface->drawPath(m_path, m_paint);
|
||||
}
|
||||
|
||||
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_fillText(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
if (const char* text = lua_tostring(L, 2)) {
|
||||
int x = lua_tointeger(L, 3);
|
||||
int y = lua_tointeger(L, 4);
|
||||
gc->fillText(text, x, y);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GraphicsContext_measureText(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
if (const char* text = lua_tostring(L, 2)) {
|
||||
push_obj(L, gc->measureText(text));
|
||||
return 1;
|
||||
}
|
||||
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_drawThemeImage(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
if (const char* id = lua_tostring(L, 2)) {
|
||||
const gfx::Point pt = convert_args_into_point(L, 3);
|
||||
gc->drawThemeImage(id, pt);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GraphicsContext_drawThemeRect(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
if (const char* id = lua_tostring(L, 2)) {
|
||||
const gfx::Rect rc = convert_args_into_rect(L, 3);
|
||||
gc->drawThemeRect(id, rc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int GraphicsContext_beginPath(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
gc->beginPath();
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GraphicsContext_closePath(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
gc->closePath();
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GraphicsContext_moveTo(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
float x = lua_tonumber(L, 2);
|
||||
float y = lua_tonumber(L, 3);
|
||||
gc->moveTo(x, y);
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GraphicsContext_lineTo(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
float x = lua_tonumber(L, 2);
|
||||
float y = lua_tonumber(L, 3);
|
||||
gc->lineTo(x, y);
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GraphicsContext_cubicTo(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
float cp1x = lua_tonumber(L, 2);
|
||||
float cp1y = lua_tonumber(L, 3);
|
||||
float cp2x = lua_tonumber(L, 4);
|
||||
float cp2y = lua_tonumber(L, 5);
|
||||
float x = lua_tonumber(L, 6);
|
||||
float y = lua_tonumber(L, 7);
|
||||
gc->cubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GraphicsContext_stroke(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
gc->stroke();
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int GraphicsContext_fill(lua_State* L)
|
||||
{
|
||||
auto gc = get_obj<GraphicsContext>(L, 1);
|
||||
gc->fill();
|
||||
lua_pushvalue(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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 },
|
||||
{ "fillText", GraphicsContext_fillText },
|
||||
{ "measureText", GraphicsContext_measureText },
|
||||
{ "drawImage", GraphicsContext_drawImage },
|
||||
{ "drawThemeImage", GraphicsContext_drawThemeImage },
|
||||
{ "drawThemeRect", GraphicsContext_drawThemeRect },
|
||||
{ "beginPath", GraphicsContext_beginPath },
|
||||
{ "closePath", GraphicsContext_closePath },
|
||||
{ "moveTo", GraphicsContext_moveTo },
|
||||
{ "lineTo", GraphicsContext_lineTo },
|
||||
{ "cubicTo", GraphicsContext_cubicTo },
|
||||
{ "stroke", GraphicsContext_stroke },
|
||||
{ "fill", GraphicsContext_fill },
|
||||
{ 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
|
107
src/app/script/graphics_context.h
Normal file
107
src/app/script/graphics_context.h
Normal file
@ -0,0 +1,107 @@
|
||||
// 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 "gfx/path.h"
|
||||
#include "os/font.h"
|
||||
#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);
|
||||
std::swap(m_paint, gc.m_paint);
|
||||
std::swap(m_font, gc.m_font);
|
||||
std::swap(m_path, gc.m_path);
|
||||
}
|
||||
|
||||
os::FontRef font() const { return m_font; }
|
||||
void font(const os::FontRef& font) { m_font = font; }
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
void fillText(const std::string& text, int x, int y);
|
||||
gfx::Size measureText(const std::string& text) const;
|
||||
|
||||
void drawImage(const doc::Image* img, int x, int y);
|
||||
|
||||
void drawThemeImage(const std::string& partId, const gfx::Point& pt);
|
||||
void drawThemeRect(const std::string& partId, const gfx::Rect& rc);
|
||||
|
||||
// Path
|
||||
void beginPath() { m_path.reset(); }
|
||||
void closePath() { m_path.close(); }
|
||||
void moveTo(float x, float y) { m_path.moveTo(x, y); }
|
||||
void lineTo(float x, float y) { m_path.lineTo(x, y); }
|
||||
void cubicTo(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y) {
|
||||
m_path.cubicTo(cp1x, cp1y, cp2x, cp2y, x, y);
|
||||
}
|
||||
void stroke();
|
||||
void fill();
|
||||
|
||||
private:
|
||||
os::SurfaceRef m_surface = nullptr;
|
||||
os::Paint m_paint;
|
||||
os::FontRef m_font;
|
||||
gfx::Path m_path;
|
||||
std::stack<os::Paint> m_saved;
|
||||
};
|
||||
|
||||
} // namespace script
|
||||
} // namespace app
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -538,6 +538,7 @@ bool ComboBoxEntry::onProcessMessage(Message* msg)
|
||||
kMouseDownMessage,
|
||||
*mouseMsg,
|
||||
mouseMsg->positionForDisplay(pick->display()));
|
||||
mouseMsg2.setRecipient(pick);
|
||||
mouseMsg2.setDisplay(pick->display());
|
||||
pick->sendMessage(&mouseMsg2);
|
||||
return true;
|
||||
|
@ -98,6 +98,7 @@ bool IntEntry::onProcessMessage(Message* msg)
|
||||
MouseMessage mouseMsg2(kMouseDownMessage,
|
||||
*mouseMsg,
|
||||
mouseMsg->positionForDisplay(pick->display()));
|
||||
mouseMsg2.setRecipient(pick);
|
||||
mouseMsg2.setDisplay(pick->display());
|
||||
pick->sendMessage(&mouseMsg2);
|
||||
}
|
||||
|
@ -1557,6 +1557,7 @@ bool Widget::onProcessMessage(Message* msg)
|
||||
MouseMessage mouseMsg2(kMouseDownMessage,
|
||||
*mouseMsg,
|
||||
mouseMsg->position());
|
||||
mouseMsg2.setRecipient(this);
|
||||
mouseMsg2.setDisplay(mouseMsg->display());
|
||||
sendMessage(&mouseMsg2);
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user