mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-06 23:09:58 +00:00
Merge branch 'main' into beta
This commit is contained in:
commit
76a815cc2c
@ -325,17 +325,15 @@ int App::initialize(const AppOptions& options)
|
|||||||
// Show the main window (this is not modal, the code continues)
|
// Show the main window (this is not modal, the code continues)
|
||||||
m_mainWindow->openWindow();
|
m_mainWindow->openWindow();
|
||||||
|
|
||||||
// Redraw the whole screen.
|
// To know the initial manager size we call to
|
||||||
manager->invalidate();
|
// Manager::updateAllDisplaysWithNewScale(...) so we receive a
|
||||||
|
// Manager::onNewDisplayConfiguration() (which will update the
|
||||||
// Pump some messages so we receive the first
|
// bounds of the manager for first time). This is required so if
|
||||||
// Manager::onNewDisplayConfiguration() and we known the manager
|
// the OpenFileCommand (called when we're processing the CLI with
|
||||||
// initial size. This is required so if the OpenFileCommand
|
// OpenBatchOfFiles) shows a dialog to open a sequence of files,
|
||||||
// (called when we're processing the CLI with OpenBatchOfFiles)
|
// the dialog is centered correctly to the manager bounds.
|
||||||
// shows a dialog to open a sequence of files, the dialog is
|
const int scale = Preferences::instance().general.screenScale();
|
||||||
// centered correctly to the manager bounds.
|
manager->updateAllDisplaysWithNewScale(scale);
|
||||||
ui::MessageLoop loop(manager);
|
|
||||||
loop.pumpMessages();
|
|
||||||
}
|
}
|
||||||
#endif // ENABLE_UI
|
#endif // ENABLE_UI
|
||||||
|
|
||||||
|
@ -70,14 +70,6 @@ Doc::Doc(Sprite* sprite)
|
|||||||
Doc::~Doc()
|
Doc::~Doc()
|
||||||
{
|
{
|
||||||
DOC_TRACE("DOC: Deleting", this);
|
DOC_TRACE("DOC: Deleting", this);
|
||||||
|
|
||||||
try {
|
|
||||||
notify_observers<Doc*>(&DocObserver::onDestroy, this);
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
LOG(ERROR, "DOC: Exception on DocObserver::onDestroy()\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
removeFromContext();
|
removeFromContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -592,6 +584,13 @@ Doc* Doc::duplicate(DuplicateType type) const
|
|||||||
|
|
||||||
void Doc::close()
|
void Doc::close()
|
||||||
{
|
{
|
||||||
|
try {
|
||||||
|
notify_observers<Doc*>(&DocObserver::onCloseDocument, this);
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
LOG(ERROR, "DOC: Exception on DocObserver::onCloseDocument()\n");
|
||||||
|
}
|
||||||
|
|
||||||
removeFromContext();
|
removeFromContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ namespace app {
|
|||||||
public:
|
public:
|
||||||
virtual ~DocObserver() { }
|
virtual ~DocObserver() { }
|
||||||
|
|
||||||
virtual void onDestroy(Doc* doc) { }
|
virtual void onCloseDocument(Doc* doc) { }
|
||||||
virtual void onFileNameChanged(Doc* doc) { }
|
virtual void onFileNameChanged(Doc* doc) { }
|
||||||
|
|
||||||
// General update. If an observer receives this event, it's because
|
// General update. If an observer receives this event, it's because
|
||||||
|
@ -506,8 +506,11 @@ bool CustomizedGuiManager::onProcessMessage(Message* msg)
|
|||||||
switch (msg->type()) {
|
switch (msg->type()) {
|
||||||
|
|
||||||
case kCloseDisplayMessage:
|
case kCloseDisplayMessage:
|
||||||
// When the main display is closed...
|
// Only call the exit command/close the app when the the main
|
||||||
if (msg->display() == this->display()) {
|
// display is the closed window in this kCloseDisplayMessage
|
||||||
|
// message and it's the current running foreground window.
|
||||||
|
if (msg->display() == this->display() &&
|
||||||
|
getForegroundWindow() == App::instance()->mainWindow()) {
|
||||||
// Execute the "Exit" command.
|
// Execute the "Exit" command.
|
||||||
Command* command = Commands::instance()->byId(CommandId::Exit());
|
Command* command = Commands::instance()->byId(CommandId::Exit());
|
||||||
UIContext::instance()->executeCommandFromMenuOrShortcut(command);
|
UIContext::instance()->executeCommandFromMenuOrShortcut(command);
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "app/doc.h"
|
#include "app/doc.h"
|
||||||
#include "app/doc_undo.h"
|
#include "app/doc_undo.h"
|
||||||
#include "app/doc_undo_observer.h"
|
#include "app/doc_undo_observer.h"
|
||||||
|
#include "app/pref/preferences.h"
|
||||||
#include "app/script/docobj.h"
|
#include "app/script/docobj.h"
|
||||||
#include "app/script/engine.h"
|
#include "app/script/engine.h"
|
||||||
#include "app/script/luacpp.h"
|
#include "app/script/luacpp.h"
|
||||||
@ -122,7 +123,7 @@ private:
|
|||||||
class AppEvents : public Events
|
class AppEvents : public Events
|
||||||
, private ContextObserver {
|
, private ContextObserver {
|
||||||
public:
|
public:
|
||||||
enum : EventType { Unknown = -1, SiteChange };
|
enum : EventType { Unknown = -1, SiteChange, FgColorChange, BgColorChange };
|
||||||
|
|
||||||
AppEvents() {
|
AppEvents() {
|
||||||
}
|
}
|
||||||
@ -130,6 +131,10 @@ public:
|
|||||||
EventType eventType(const char* eventName) const {
|
EventType eventType(const char* eventName) const {
|
||||||
if (std::strcmp(eventName, "sitechange") == 0)
|
if (std::strcmp(eventName, "sitechange") == 0)
|
||||||
return SiteChange;
|
return SiteChange;
|
||||||
|
else if (std::strcmp(eventName, "fgcolorchange") == 0)
|
||||||
|
return FgColorChange;
|
||||||
|
else if (std::strcmp(eventName, "bgcolorchange") == 0)
|
||||||
|
return BgColorChange;
|
||||||
else
|
else
|
||||||
return Unknown;
|
return Unknown;
|
||||||
}
|
}
|
||||||
@ -138,24 +143,49 @@ private:
|
|||||||
|
|
||||||
void onAddFirstListener(EventType eventType) override {
|
void onAddFirstListener(EventType eventType) override {
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case SiteChange: {
|
case SiteChange:
|
||||||
App::instance()->context()->add_observer(this);
|
App::instance()->context()->add_observer(this);
|
||||||
break;
|
break;
|
||||||
}
|
case FgColorChange:
|
||||||
|
m_fgConn = Preferences::instance().colorBar.fgColor
|
||||||
|
.AfterChange.connect([this]{ onFgColorChange(); });
|
||||||
|
break;
|
||||||
|
case BgColorChange:
|
||||||
|
m_bgConn = Preferences::instance().colorBar.bgColor
|
||||||
|
.AfterChange.connect([this]{ onBgColorChange(); });
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRemoveLastListener(EventType eventType) override {
|
void onRemoveLastListener(EventType eventType) override {
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case SiteChange: {
|
case SiteChange:
|
||||||
App::instance()->context()->remove_observer(this);
|
App::instance()->context()->remove_observer(this);
|
||||||
break;
|
break;
|
||||||
}
|
case FgColorChange:
|
||||||
|
m_fgConn.disconnect();
|
||||||
|
break;
|
||||||
|
case BgColorChange:
|
||||||
|
m_bgConn.disconnect();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onFgColorChange() {
|
||||||
|
call(FgColorChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onBgColorChange() {
|
||||||
|
call(BgColorChange);
|
||||||
|
}
|
||||||
|
|
||||||
// ContextObserver impl
|
// ContextObserver impl
|
||||||
void onActiveSiteChange(const Site& site) override { call(SiteChange); }
|
void onActiveSiteChange(const Site& site) override {
|
||||||
|
call(SiteChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs::scoped_connection m_fgConn;
|
||||||
|
obs::scoped_connection m_bgConn;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SpriteEvents : public Events
|
class SpriteEvents : public Events
|
||||||
@ -170,11 +200,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
~SpriteEvents() {
|
~SpriteEvents() {
|
||||||
if (m_observingUndo) {
|
auto doc = this->doc();
|
||||||
doc()->undoHistory()->remove_observer(this);
|
ASSERT(doc);
|
||||||
m_observingUndo = false;
|
if (doc) {
|
||||||
|
disconnectFromUndoHistory(doc);
|
||||||
|
doc->remove_observer(this);
|
||||||
}
|
}
|
||||||
doc()->remove_observer(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EventType eventType(const char* eventName) const {
|
EventType eventType(const char* eventName) const {
|
||||||
@ -185,11 +216,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DocObserver impl
|
// DocObserver impl
|
||||||
void onDestroy(Doc* doc) override {
|
void onCloseDocument(Doc* doc) override {
|
||||||
auto it = g_spriteEvents.find(m_spriteId);
|
auto it = g_spriteEvents.find(m_spriteId);
|
||||||
ASSERT(it != g_spriteEvents.end());
|
ASSERT(it != g_spriteEvents.end());
|
||||||
if (it != g_spriteEvents.end())
|
if (it != g_spriteEvents.end()) {
|
||||||
|
// As this is an unique_ptr, here we are calling ~SpriteEvents()
|
||||||
g_spriteEvents.erase(it);
|
g_spriteEvents.erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DocUndoObserver impl
|
// DocUndoObserver impl
|
||||||
@ -211,10 +244,7 @@ private:
|
|||||||
void onRemoveLastListener(EventType eventType) override {
|
void onRemoveLastListener(EventType eventType) override {
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case Change: {
|
case Change: {
|
||||||
if (m_observingUndo) {
|
disconnectFromUndoHistory(doc());
|
||||||
doc()->undoHistory()->remove_observer(this);
|
|
||||||
m_observingUndo = false;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,6 +258,13 @@ private:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void disconnectFromUndoHistory(Doc* doc) {
|
||||||
|
if (m_observingUndo) {
|
||||||
|
doc->undoHistory()->remove_observer(this);
|
||||||
|
m_observingUndo = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ObjectId m_spriteId;
|
ObjectId m_spriteId;
|
||||||
bool m_observingUndo = false;
|
bool m_observingUndo = false;
|
||||||
};
|
};
|
||||||
|
@ -13,11 +13,14 @@
|
|||||||
#include "app/script/engine.h"
|
#include "app/script/engine.h"
|
||||||
#include "app/script/luacpp.h"
|
#include "app/script/luacpp.h"
|
||||||
#include "app/script/security.h"
|
#include "app/script/security.h"
|
||||||
|
#include "ui/timer.h"
|
||||||
|
#include "ui/manager.h"
|
||||||
#include "ui/system.h"
|
#include "ui/system.h"
|
||||||
|
|
||||||
#include <ixwebsocket/IXNetSystem.h>
|
#include <ixwebsocket/IXNetSystem.h>
|
||||||
#include <ixwebsocket/IXWebSocket.h>
|
#include <ixwebsocket/IXWebSocket.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
namespace script {
|
namespace script {
|
||||||
@ -27,6 +30,18 @@ namespace {
|
|||||||
// Additional "enum" value to make message callback simpler
|
// Additional "enum" value to make message callback simpler
|
||||||
#define MESSAGE_TYPE_BINARY ((int)ix::WebSocketMessageType::Fragment + 10)
|
#define MESSAGE_TYPE_BINARY ((int)ix::WebSocketMessageType::Fragment + 10)
|
||||||
|
|
||||||
|
static std::unique_ptr<ui::Timer> g_timer;
|
||||||
|
static std::set<ix::WebSocket*> g_connections;
|
||||||
|
|
||||||
|
static void close_ws(ix::WebSocket* ws)
|
||||||
|
{
|
||||||
|
ws->stop();
|
||||||
|
|
||||||
|
g_connections.erase(ws);
|
||||||
|
if (g_connections.empty())
|
||||||
|
g_timer.reset();
|
||||||
|
}
|
||||||
|
|
||||||
int WebSocket_new(lua_State* L)
|
int WebSocket_new(lua_State* L)
|
||||||
{
|
{
|
||||||
static std::once_flag f;
|
static std::once_flag f;
|
||||||
@ -55,7 +70,19 @@ int WebSocket_new(lua_State* L)
|
|||||||
}
|
}
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
int type = lua_getfield(L, 1, "onreceive");
|
int type = lua_getfield(L, 1, "minreconnectwait");
|
||||||
|
if (type == LUA_TNUMBER) {
|
||||||
|
ws->setMinWaitBetweenReconnectionRetries(1000 * lua_tonumber(L, -1));
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
type = lua_getfield(L, 1, "maxreconnectwait");
|
||||||
|
if (type == LUA_TNUMBER) {
|
||||||
|
ws->setMaxWaitBetweenReconnectionRetries(1000 * lua_tonumber(L, -1));
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
type = lua_getfield(L, 1, "onreceive");
|
||||||
if (type == LUA_TFUNCTION) {
|
if (type == LUA_TFUNCTION) {
|
||||||
int onreceiveRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
int onreceiveRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
@ -80,6 +107,8 @@ int WebSocket_new(lua_State* L)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// Set a default handler to avoid a std::bad_function_call exception
|
||||||
|
ws->setOnMessageCallback([](const ix::WebSocketMessagePtr& msg) { });
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,7 +119,7 @@ int WebSocket_new(lua_State* L)
|
|||||||
int WebSocket_gc(lua_State* L)
|
int WebSocket_gc(lua_State* L)
|
||||||
{
|
{
|
||||||
auto ws = get_ptr<ix::WebSocket>(L, 1);
|
auto ws = get_ptr<ix::WebSocket>(L, 1);
|
||||||
ws->stop();
|
close_ws(ws);
|
||||||
delete ws;
|
delete ws;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -151,13 +180,24 @@ int WebSocket_connect(lua_State* L)
|
|||||||
{
|
{
|
||||||
auto ws = get_ptr<ix::WebSocket>(L, 1);
|
auto ws = get_ptr<ix::WebSocket>(L, 1);
|
||||||
ws->start();
|
ws->start();
|
||||||
|
|
||||||
|
if (g_connections.empty()) {
|
||||||
|
#ifdef ENABLE_UI
|
||||||
|
if (App::instance()->isGui()) {
|
||||||
|
g_timer = std::make_unique<ui::Timer>(33, ui::Manager::getDefault());
|
||||||
|
g_timer->start();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
g_connections.insert(ws);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WebSocket_close(lua_State* L)
|
int WebSocket_close(lua_State* L)
|
||||||
{
|
{
|
||||||
auto ws = get_ptr<ix::WebSocket>(L, 1);
|
auto ws = get_ptr<ix::WebSocket>(L, 1);
|
||||||
ws->stop();
|
close_ws(ws);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,14 +238,14 @@ void register_websocket_class(lua_State* L)
|
|||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
lua_pushvalue(L, -1);
|
lua_pushvalue(L, -1);
|
||||||
lua_setglobal(L, "WebSocketMessageType");
|
lua_setglobal(L, "WebSocketMessageType");
|
||||||
setfield_integer(L, "Text", (int)ix::WebSocketMessageType::Message);
|
setfield_integer(L, "TEXT", (int)ix::WebSocketMessageType::Message);
|
||||||
setfield_integer(L, "Binary", MESSAGE_TYPE_BINARY);
|
setfield_integer(L, "BINARY", MESSAGE_TYPE_BINARY);
|
||||||
setfield_integer(L, "Open", (int)ix::WebSocketMessageType::Open);
|
setfield_integer(L, "OPEN", (int)ix::WebSocketMessageType::Open);
|
||||||
setfield_integer(L, "Close", (int)ix::WebSocketMessageType::Close);
|
setfield_integer(L, "CLOSE", (int)ix::WebSocketMessageType::Close);
|
||||||
setfield_integer(L, "Error", (int)ix::WebSocketMessageType::Error);
|
setfield_integer(L, "ERROR", (int)ix::WebSocketMessageType::Error);
|
||||||
setfield_integer(L, "Ping", (int)ix::WebSocketMessageType::Ping);
|
setfield_integer(L, "PING", (int)ix::WebSocketMessageType::Ping);
|
||||||
setfield_integer(L, "Pong", (int)ix::WebSocketMessageType::Pong);
|
setfield_integer(L, "PONG", (int)ix::WebSocketMessageType::Pong);
|
||||||
setfield_integer(L, "Fragment", (int)ix::WebSocketMessageType::Fragment);
|
setfield_integer(L, "FRAGMENT", (int)ix::WebSocketMessageType::Fragment);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,10 +394,12 @@ Widget* WidgetLoader::convertXmlElementToWidget(const TiXmlElement* elem, Widget
|
|||||||
else if (elem_name == "slider") {
|
else if (elem_name == "slider") {
|
||||||
const char *min = elem->Attribute("min");
|
const char *min = elem->Attribute("min");
|
||||||
const char *max = elem->Attribute("max");
|
const char *max = elem->Attribute("max");
|
||||||
|
const bool readonly = bool_attr(elem, "readonly", false);
|
||||||
int min_value = (min ? strtol(min, nullptr, 10): 0);
|
int min_value = (min ? strtol(min, nullptr, 10): 0);
|
||||||
int max_value = (max ? strtol(max, nullptr, 10): 0);
|
int max_value = (max ? strtol(max, nullptr, 10): 0);
|
||||||
|
|
||||||
widget = new Slider(min_value, max_value, min_value);
|
widget = new Slider(min_value, max_value, min_value);
|
||||||
|
static_cast<Slider*>(widget)->setReadOnly(readonly);
|
||||||
}
|
}
|
||||||
else if (elem_name == "textbox") {
|
else if (elem_name == "textbox") {
|
||||||
const char* text = (elem->GetText() ? elem->GetText(): "");
|
const char* text = (elem->GetText() ? elem->GetText(): "");
|
||||||
|
@ -133,6 +133,9 @@ static Item convert_to_item(TiXmlElement* elem)
|
|||||||
if (name == "listbox")
|
if (name == "listbox")
|
||||||
return item.typeIncl("ui::ListBox",
|
return item.typeIncl("ui::ListBox",
|
||||||
"ui/listbox.h");
|
"ui/listbox.h");
|
||||||
|
if (name == "listitem")
|
||||||
|
return item.typeIncl("ui::ListItem",
|
||||||
|
"ui/listitem.h");
|
||||||
if (name == "panel")
|
if (name == "panel")
|
||||||
return item.typeIncl("ui::Panel",
|
return item.typeIncl("ui::Panel",
|
||||||
"ui/panel.h");
|
"ui/panel.h");
|
||||||
|
Loading…
Reference in New Issue
Block a user