mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 13:21:34 +00:00
Support drag and drop images as new documents
This commit is contained in:
parent
573822d9f1
commit
365bad61d5
@ -689,6 +689,7 @@ target_sources(app-lib PRIVATE
|
||||
util/cel_ops.cpp
|
||||
util/clipboard.cpp
|
||||
util/clipboard_native.cpp
|
||||
util/conversion_to_image.cpp
|
||||
util/conversion_to_surface.cpp
|
||||
util/expand_cel_canvas.cpp
|
||||
util/filetoks.cpp
|
||||
|
@ -46,6 +46,7 @@ struct NewFileParams : public NewParams {
|
||||
Param<int> height { this, 0, "height" };
|
||||
Param<ColorMode> colorMode { this, ColorMode::RGB, "colorMode" };
|
||||
Param<bool> fromClipboard { this, false, "fromClipboard" };
|
||||
Param<bool> fromDraggedData { this, false, "fromDraggedData" };
|
||||
};
|
||||
|
||||
class NewFileCommand : public CommandWithNewParams<NewFileParams> {
|
||||
@ -86,8 +87,9 @@ void NewFileCommand::onExecute(Context* ctx)
|
||||
doc::Palette clipboardPalette(0, 256);
|
||||
const int ncolors = get_default_palette()->size();
|
||||
|
||||
if (params().fromClipboard()) {
|
||||
clipboardImage = ctx->clipboard()->getImage(&clipboardPalette);
|
||||
if (params().fromClipboard() || params().fromDraggedData()) {
|
||||
clipboardImage = (params().fromClipboard() ? ctx->clipboard()->getImage(&clipboardPalette)
|
||||
: ctx->draggedData()->getImage());
|
||||
if (!clipboardImage)
|
||||
return;
|
||||
|
||||
|
@ -14,11 +14,14 @@
|
||||
#include "app/context_observer.h"
|
||||
#include "app/docs.h"
|
||||
#include "app/docs_observer.h"
|
||||
#include "app/util/conversion_to_image.h"
|
||||
#include "base/disable_copying.h"
|
||||
#include "base/exception.h"
|
||||
#include "doc/frame.h"
|
||||
#include "doc/image_ref.h"
|
||||
#include "obs/observable.h"
|
||||
#include "obs/signal.h"
|
||||
#include "os/surface.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@ -86,6 +89,22 @@ namespace app {
|
||||
bool m_canceled;
|
||||
};
|
||||
|
||||
class DraggedData
|
||||
{
|
||||
public:
|
||||
DraggedData(const doc::ImageRef& image) {
|
||||
m_image = image;
|
||||
}
|
||||
DraggedData(const os::SurfaceRef& surface) {
|
||||
convert_surface_to_image(surface.get(), 0, 0, surface->width(), surface->height(), m_image);
|
||||
}
|
||||
|
||||
const doc::ImageRef& getImage() const { return m_image; }
|
||||
|
||||
private:
|
||||
doc::ImageRef m_image = nullptr;
|
||||
};
|
||||
|
||||
class Context : public obs::observable<ContextObserver>,
|
||||
public DocsObserver {
|
||||
public:
|
||||
@ -120,6 +139,11 @@ namespace app {
|
||||
bool hasModifiedDocuments() const;
|
||||
void notifyActiveSiteChanged();
|
||||
|
||||
void setDraggedData(std::unique_ptr<DraggedData> draggedData) {
|
||||
m_draggedData = std::move(draggedData);
|
||||
}
|
||||
const DraggedData* draggedData() const { return m_draggedData.get(); }
|
||||
|
||||
void executeCommandFromMenuOrShortcut(Command* command, const Params& params = Params());
|
||||
virtual void executeCommand(Command* command, const Params& params = Params());
|
||||
|
||||
@ -159,6 +183,7 @@ namespace app {
|
||||
ContextFlags m_flags; // Last updated flags.
|
||||
Doc* m_lastSelectedDoc;
|
||||
mutable std::unique_ptr<Preferences> m_preferences;
|
||||
std::unique_ptr<DraggedData> m_draggedData = nullptr;
|
||||
|
||||
// Result of the execution of a command.
|
||||
CommandResult m_result;
|
||||
|
@ -39,7 +39,10 @@
|
||||
#include "app/ui/workspace_tabs.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/fs.h"
|
||||
#include "os/event.h"
|
||||
#include "os/event_queue.h"
|
||||
#include "os/system.h"
|
||||
#include "ui/drag_event.h"
|
||||
#include "ui/message.h"
|
||||
#include "ui/splitter.h"
|
||||
#include "ui/system.h"
|
||||
@ -91,6 +94,7 @@ MainWindow::MainWindow()
|
||||
, m_devConsoleView(nullptr)
|
||||
#endif
|
||||
{
|
||||
enableFlags(ALLOW_DROP);
|
||||
}
|
||||
|
||||
// This 'initialize' function is a way to split the creation of the
|
||||
@ -434,6 +438,22 @@ void MainWindow::onActiveViewChange()
|
||||
UIContext::instance()->setActiveView(nullptr);
|
||||
}
|
||||
|
||||
void MainWindow::onDrop(ui::DragEvent& e)
|
||||
{
|
||||
if (e.hasImage()) {
|
||||
auto* cmd = Commands::instance()->byId(CommandId::NewFile());
|
||||
Params params;
|
||||
params.set("fromDraggedData", "true");
|
||||
UIContext::instance()->setDraggedData(std::make_unique<DraggedData>(e.getImage()));
|
||||
UIContext::instance()->executeCommand(cmd, params);
|
||||
e.handled(true);
|
||||
invalidate();
|
||||
flushRedraw();
|
||||
os::Event ev;
|
||||
os::System::instance()->eventQueue()->queueEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
bool MainWindow::isTabModified(Tabs* tabs, TabView* tabView)
|
||||
{
|
||||
if (DocView* docView = dynamic_cast<DocView*>(tabView)) {
|
||||
|
@ -119,6 +119,8 @@ namespace app {
|
||||
void onActiveViewChange();
|
||||
void onLanguageChange();
|
||||
|
||||
void onDrop(ui::DragEvent& e) override;
|
||||
|
||||
private:
|
||||
DocView* getDocView();
|
||||
HomeView* getHomeView();
|
||||
|
53
src/app/util/conversion_to_image.cpp
Normal file
53
src/app/util/conversion_to_image.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2024 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/util/conversion_to_image.h"
|
||||
|
||||
#include "doc/image_traits.h"
|
||||
#include "doc/pixel_format.h"
|
||||
#include "os/surface.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace doc;
|
||||
|
||||
// TODO: This implementation has a lot of room for improvement, I made the bare
|
||||
// minimum to make it work. Right now it only supports converting RGBA surfaces,
|
||||
// other kind of surfaces won't be converted to an image as expected.
|
||||
void convert_surface_to_image(
|
||||
const os::Surface* surface,
|
||||
int src_x, int src_y,
|
||||
int w, int h,
|
||||
ImageRef& image)
|
||||
{
|
||||
gfx::Rect srcBounds(src_x, src_y, w, h);
|
||||
srcBounds = srcBounds.createIntersection(surface->getClipBounds());
|
||||
if (srcBounds.isEmpty())
|
||||
return;
|
||||
|
||||
src_x = srcBounds.x;
|
||||
src_y = srcBounds.y;
|
||||
w = srcBounds.w;
|
||||
h = srcBounds.h;
|
||||
|
||||
image.reset(Image::create(PixelFormat::IMAGE_RGB, w, h));
|
||||
|
||||
for (int v=0; v<h; ++v, ++src_y) {
|
||||
uint8_t* src_address = surface->getData(0, v);
|
||||
uint8_t* dst_address = image->getPixelAddress(src_x, src_y);
|
||||
std::copy(src_address,
|
||||
src_address + RgbTraits::bytes_per_pixel * w,
|
||||
dst_address);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
31
src/app/util/conversion_to_image.h
Normal file
31
src/app/util/conversion_to_image.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Aseprite
|
||||
// Copyright (c) 2024 Igara Studio S.A.
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
// the End-User License Agreement for Aseprite.
|
||||
|
||||
#ifndef APP_UTIL_CONVERSION_TO_IMAGE_H_INCLUDED
|
||||
#define APP_UTIL_CONVERSION_TO_IMAGE_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "doc/image_ref.h"
|
||||
|
||||
namespace os {
|
||||
class Surface;
|
||||
}
|
||||
|
||||
namespace doc {
|
||||
class Palette;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
|
||||
void convert_surface_to_image(
|
||||
const os::Surface* surface,
|
||||
int src_x, int src_y,
|
||||
int w, int h,
|
||||
doc::ImageRef& image);
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -2056,7 +2056,7 @@ void Manager::dragEnter(os::DragEvent& ev)
|
||||
{
|
||||
Widget* widget = pickForDragAndDrop(ev.position());
|
||||
|
||||
ASSERT(widget->hasFlags(ALLOW_DROP));
|
||||
ASSERT(!widget || widget && widget->hasFlags(ALLOW_DROP));
|
||||
|
||||
if (widget) {
|
||||
m_dragOverWidget = widget;
|
||||
@ -2080,7 +2080,7 @@ void Manager::drag(os::DragEvent& ev)
|
||||
{
|
||||
Widget* widget = pickForDragAndDrop(ev.position());
|
||||
|
||||
ASSERT(widget->hasFlags(ALLOW_DROP));
|
||||
ASSERT(!widget || widget && widget->hasFlags(ALLOW_DROP));
|
||||
|
||||
if (m_dragOverWidget && m_dragOverWidget != widget) {
|
||||
DragEvent uiev(this, m_dragOverWidget, ev);
|
||||
@ -2104,7 +2104,7 @@ void Manager::drop(os::DragEvent& ev)
|
||||
m_dragOverWidget = nullptr;
|
||||
Widget* widget = pickForDragAndDrop(ev.position());
|
||||
|
||||
ASSERT(widget->hasFlags(ALLOW_DROP));
|
||||
ASSERT(!widget || widget && widget->hasFlags(ALLOW_DROP));
|
||||
|
||||
if (widget) {
|
||||
DragEvent uiev(this, widget, ev);
|
||||
|
Loading…
x
Reference in New Issue
Block a user