2015-02-12 23:16:25 +08:00
|
|
|
// Aseprite
|
|
|
|
// Copyright (C) 2001-2015 David Capello
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License version 2 as
|
|
|
|
// published by the Free Software Foundation.
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2012-01-06 06:45:03 +08:00
|
|
|
#include "config.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#endif
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "ui/ui.h"
|
|
|
|
|
|
|
|
#include "app/app.h"
|
2014-12-28 22:06:11 +08:00
|
|
|
#include "app/app_render.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/commands/command.h"
|
|
|
|
#include "app/commands/commands.h"
|
|
|
|
#include "app/context.h"
|
|
|
|
#include "app/modules/editors.h"
|
|
|
|
#include "app/modules/gfx.h"
|
2015-02-15 20:48:38 +08:00
|
|
|
#include "app/pref/preferences.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/editor/editor.h"
|
2014-10-29 22:58:03 +08:00
|
|
|
#include "app/ui/keyboard_shortcuts.h"
|
2013-08-06 08:20:19 +08:00
|
|
|
#include "app/ui/status_bar.h"
|
2014-10-21 09:21:31 +08:00
|
|
|
#include "doc/conversion_she.h"
|
|
|
|
#include "doc/image.h"
|
|
|
|
#include "doc/palette.h"
|
|
|
|
#include "doc/primitives.h"
|
|
|
|
#include "doc/sprite.h"
|
2014-08-10 08:33:38 +08:00
|
|
|
#include "she/scoped_handle.h"
|
|
|
|
#include "she/surface.h"
|
|
|
|
#include "she/system.h"
|
2012-06-18 09:02:54 +08:00
|
|
|
|
2015-03-05 08:35:11 +08:00
|
|
|
#include <cstring>
|
|
|
|
|
2012-01-06 06:45:03 +08:00
|
|
|
#define PREVIEW_TILED 1
|
|
|
|
#define PREVIEW_FIT_ON_SCREEN 2
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
namespace app {
|
2012-01-06 06:45:03 +08:00
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
using namespace ui;
|
2014-10-21 09:21:31 +08:00
|
|
|
using namespace doc;
|
2013-08-06 08:20:19 +08:00
|
|
|
using namespace filters;
|
|
|
|
|
2014-08-09 21:37:51 +08:00
|
|
|
class PreviewWindow : public Window {
|
|
|
|
public:
|
|
|
|
PreviewWindow(Context* context, Editor* editor)
|
|
|
|
: Window(DesktopWindow)
|
|
|
|
, m_context(context)
|
|
|
|
, m_editor(editor)
|
|
|
|
, m_doc(editor->document())
|
|
|
|
, m_sprite(editor->sprite())
|
2014-12-29 07:39:11 +08:00
|
|
|
, m_pal(m_sprite->palette(editor->frame()))
|
2015-01-21 22:35:35 +08:00
|
|
|
, m_zoom(editor->zoom())
|
2014-08-09 21:37:51 +08:00
|
|
|
, m_index_bg_color(-1)
|
2014-09-01 01:17:49 +08:00
|
|
|
, m_doublebuf(Image::create(IMAGE_RGB, ui::display_w(), ui::display_h()))
|
2015-01-21 22:35:35 +08:00
|
|
|
, m_doublesur(she::instance()->createRgbaSurface(ui::display_w(), ui::display_h())) {
|
2014-08-09 21:37:51 +08:00
|
|
|
// Do not use DocumentWriter (do not lock the document) because we
|
|
|
|
// will call other sub-commands (e.g. previous frame, next frame,
|
|
|
|
// etc.).
|
|
|
|
View* view = View::getView(editor);
|
2015-05-19 03:53:25 +08:00
|
|
|
DocumentPreferences& docPref = Preferences::instance().document(m_doc);
|
2015-02-15 20:48:38 +08:00
|
|
|
m_tiled = (filters::TiledMode)docPref.tiled.mode();
|
2014-08-09 21:37:51 +08:00
|
|
|
|
|
|
|
// Free mouse
|
|
|
|
editor->getManager()->freeMouse();
|
|
|
|
|
|
|
|
// Clear extras (e.g. pen preview)
|
2015-08-19 21:03:29 +08:00
|
|
|
m_doc->setExtraCel(ExtraCelRef(nullptr));
|
2014-08-09 21:37:51 +08:00
|
|
|
|
|
|
|
gfx::Rect vp = view->getViewportBounds();
|
|
|
|
gfx::Point scroll = view->getViewScroll();
|
|
|
|
|
2014-08-26 08:49:37 +08:00
|
|
|
m_oldMousePos = ui::get_mouse_position();
|
2015-08-04 23:26:58 +08:00
|
|
|
m_pos.x = -scroll.x + vp.x + editor->padding().x;
|
|
|
|
m_pos.y = -scroll.y + vp.y + editor->padding().y;
|
2014-08-09 21:37:51 +08:00
|
|
|
|
2014-08-10 04:31:22 +08:00
|
|
|
setFocusStop(true);
|
|
|
|
captureMouse();
|
2014-08-09 21:37:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
2014-08-15 10:07:47 +08:00
|
|
|
virtual bool onProcessMessage(Message* msg) override {
|
2014-08-09 21:37:51 +08:00
|
|
|
switch (msg->type()) {
|
|
|
|
|
|
|
|
case kCloseMessage:
|
2014-08-10 04:31:22 +08:00
|
|
|
releaseMouse();
|
2014-08-09 21:37:51 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case kMouseMoveMessage: {
|
|
|
|
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
|
|
|
gfx::Point mousePos = mouseMsg->position();
|
|
|
|
|
|
|
|
gfx::Rect bounds = getBounds();
|
|
|
|
gfx::Border border;
|
2014-11-26 09:33:45 +08:00
|
|
|
if (bounds.w > 64*guiscale()) {
|
|
|
|
border.left(32*guiscale());
|
|
|
|
border.right(32*guiscale());
|
2014-08-09 21:37:51 +08:00
|
|
|
}
|
2014-11-26 09:33:45 +08:00
|
|
|
if (bounds.h > 64*guiscale()) {
|
|
|
|
border.top(32*guiscale());
|
|
|
|
border.bottom(32*guiscale());
|
2014-08-09 21:37:51 +08:00
|
|
|
}
|
|
|
|
|
2014-08-26 08:49:37 +08:00
|
|
|
m_delta += mousePos - m_oldMousePos;
|
|
|
|
m_oldMousePos = mousePos;
|
2014-08-09 21:37:51 +08:00
|
|
|
|
|
|
|
invalidate();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case kMouseUpMessage: {
|
|
|
|
closeWindow(this);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case kKeyDownMessage: {
|
|
|
|
KeyMessage* keyMsg = static_cast<KeyMessage*>(msg);
|
|
|
|
Command* command = NULL;
|
2015-03-12 02:40:22 +08:00
|
|
|
Params params;
|
2014-10-29 22:58:03 +08:00
|
|
|
KeyboardShortcuts::instance()
|
2015-03-12 02:40:22 +08:00
|
|
|
->getCommandFromKeyMessage(msg, &command, ¶ms);
|
2014-08-09 21:37:51 +08:00
|
|
|
|
|
|
|
// Change frame
|
|
|
|
if (command != NULL &&
|
2015-05-02 06:41:18 +08:00
|
|
|
(command->id() == CommandId::GotoFirstFrame ||
|
|
|
|
command->id() == CommandId::GotoPreviousFrame ||
|
|
|
|
command->id() == CommandId::GotoNextFrame ||
|
|
|
|
command->id() == CommandId::GotoLastFrame)) {
|
2015-03-12 02:40:22 +08:00
|
|
|
m_context->executeCommand(command, params);
|
2014-08-09 21:37:51 +08:00
|
|
|
invalidate();
|
|
|
|
m_render.reset(NULL); // Re-render
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
// Play the animation
|
|
|
|
else if (command != NULL &&
|
2015-03-05 08:35:11 +08:00
|
|
|
std::strcmp(command->short_name(), CommandId::PlayAnimation) == 0) {
|
2014-08-09 21:37:51 +08:00
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// Change background color
|
|
|
|
else if (keyMsg->scancode() == kKeyPlusPad ||
|
|
|
|
keyMsg->unicodeChar() == '+') {
|
|
|
|
if (m_index_bg_color == -1 ||
|
|
|
|
m_index_bg_color < m_pal->size()-1) {
|
|
|
|
++m_index_bg_color;
|
|
|
|
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (keyMsg->scancode() == kKeyMinusPad ||
|
|
|
|
keyMsg->unicodeChar() == '-') {
|
|
|
|
if (m_index_bg_color >= 0) {
|
|
|
|
--m_index_bg_color; // can be -1 which is the checked background
|
|
|
|
|
|
|
|
invalidate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
closeWindow(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
case kSetCursorMessage:
|
2014-11-26 08:30:56 +08:00
|
|
|
ui::set_mouse_cursor(kNoCursor);
|
2014-08-09 21:37:51 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Window::onProcessMessage(msg);
|
|
|
|
}
|
|
|
|
|
2014-08-15 10:07:47 +08:00
|
|
|
virtual void onPaint(PaintEvent& ev) override {
|
2014-08-09 21:37:51 +08:00
|
|
|
Graphics* g = ev.getGraphics();
|
2015-08-20 00:05:45 +08:00
|
|
|
AppRender& render = m_editor->renderEngine();
|
2014-12-28 22:06:11 +08:00
|
|
|
render.disableOnionskin();
|
|
|
|
render.setBgType(render::BgType::TRANSPARENT);
|
2014-08-09 21:37:51 +08:00
|
|
|
|
2014-12-28 22:06:11 +08:00
|
|
|
// Render sprite and leave the result in 'm_render' variable
|
2014-08-09 21:37:51 +08:00
|
|
|
if (m_render == NULL) {
|
2014-11-30 23:06:31 +08:00
|
|
|
ImageBufferPtr buf = Editor::getRenderImageBuffer();
|
2014-12-28 22:06:11 +08:00
|
|
|
m_render.reset(Image::create(IMAGE_RGB,
|
|
|
|
m_sprite->width(), m_sprite->height(), buf));
|
|
|
|
|
|
|
|
render.renderSprite(
|
|
|
|
m_render.get(), m_sprite, m_editor->frame());
|
2014-08-09 21:37:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int x, y, w, h, u, v;
|
2014-11-25 04:18:30 +08:00
|
|
|
x = m_pos.x + m_zoom.apply(m_zoom.remove(m_delta.x));
|
|
|
|
y = m_pos.y + m_zoom.apply(m_zoom.remove(m_delta.y));
|
|
|
|
w = m_zoom.apply(m_sprite->width());
|
|
|
|
h = m_zoom.apply(m_sprite->height());
|
2014-08-09 21:37:51 +08:00
|
|
|
|
2015-02-15 20:48:38 +08:00
|
|
|
if (int(m_tiled) & int(TiledMode::X_AXIS)) x = SGN(x) * (ABS(x)%w);
|
|
|
|
if (int(m_tiled) & int(TiledMode::Y_AXIS)) y = SGN(y) * (ABS(y)%h);
|
2014-08-09 21:37:51 +08:00
|
|
|
|
2014-12-28 22:06:11 +08:00
|
|
|
if (m_index_bg_color == -1) {
|
|
|
|
render.setupBackground(m_doc, m_doublebuf->pixelFormat());
|
|
|
|
render.renderBackground(m_doublebuf,
|
|
|
|
gfx::Clip(0, 0, -m_pos.x, -m_pos.y,
|
|
|
|
m_doublebuf->width(), m_doublebuf->height()), m_zoom);
|
|
|
|
}
|
|
|
|
else {
|
2014-10-21 09:21:31 +08:00
|
|
|
doc::clear_image(m_doublebuf, m_pal->getEntry(m_index_bg_color));
|
2014-12-28 22:06:11 +08:00
|
|
|
}
|
2014-08-09 21:37:51 +08:00
|
|
|
|
|
|
|
switch (m_tiled) {
|
2015-02-15 20:48:38 +08:00
|
|
|
case TiledMode::NONE:
|
2014-12-28 22:06:11 +08:00
|
|
|
render.renderImage(m_doublebuf, m_render, m_pal, x, y,
|
2015-06-14 08:29:16 +08:00
|
|
|
m_zoom, 255, BlendMode::NORMAL);
|
2014-08-09 21:37:51 +08:00
|
|
|
break;
|
2015-02-15 20:48:38 +08:00
|
|
|
case TiledMode::X_AXIS:
|
2014-09-01 01:17:49 +08:00
|
|
|
for (u=x-w; u<ui::display_w()+w; u+=w)
|
2014-12-28 22:06:11 +08:00
|
|
|
render.renderImage(m_doublebuf, m_render, m_pal, u, y,
|
2015-06-14 08:29:16 +08:00
|
|
|
m_zoom, 255, BlendMode::NORMAL);
|
2014-08-09 21:37:51 +08:00
|
|
|
break;
|
2015-02-15 20:48:38 +08:00
|
|
|
case TiledMode::Y_AXIS:
|
2014-09-01 01:17:49 +08:00
|
|
|
for (v=y-h; v<ui::display_h()+h; v+=h)
|
2014-12-28 22:06:11 +08:00
|
|
|
render.renderImage(m_doublebuf, m_render, m_pal, x, v,
|
2015-06-14 08:29:16 +08:00
|
|
|
m_zoom, 255, BlendMode::NORMAL);
|
2014-08-09 21:37:51 +08:00
|
|
|
break;
|
2015-02-15 20:48:38 +08:00
|
|
|
case TiledMode::BOTH:
|
2014-09-01 01:17:49 +08:00
|
|
|
for (v=y-h; v<ui::display_h()+h; v+=h)
|
|
|
|
for (u=x-w; u<ui::display_w()+w; u+=w)
|
2014-12-28 22:06:11 +08:00
|
|
|
render.renderImage(m_doublebuf, m_render, m_pal, u, v,
|
2015-06-14 08:29:16 +08:00
|
|
|
m_zoom, 255, BlendMode::NORMAL);
|
2014-08-09 21:37:51 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-10-21 09:21:31 +08:00
|
|
|
doc::convert_image_to_surface(m_doublebuf, m_pal,
|
2014-08-10 08:33:38 +08:00
|
|
|
m_doublesur, 0, 0, 0, 0, m_doublebuf->width(), m_doublebuf->height());
|
|
|
|
g->blit(m_doublesur, 0, 0, 0, 0, m_doublesur->width(), m_doublesur->height());
|
2014-08-09 21:37:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Context* m_context;
|
|
|
|
Editor* m_editor;
|
|
|
|
Document* m_doc;
|
|
|
|
Sprite* m_sprite;
|
|
|
|
const Palette* m_pal;
|
|
|
|
gfx::Point m_pos;
|
2014-08-26 08:49:37 +08:00
|
|
|
gfx::Point m_oldMousePos;
|
2014-08-09 21:37:51 +08:00
|
|
|
gfx::Point m_delta;
|
2014-12-28 22:06:11 +08:00
|
|
|
render::Zoom m_zoom;
|
2014-08-09 21:37:51 +08:00
|
|
|
int m_index_bg_color;
|
|
|
|
base::UniquePtr<Image> m_render;
|
|
|
|
base::UniquePtr<Image> m_doublebuf;
|
2014-08-10 08:33:38 +08:00
|
|
|
she::ScopedHandle<she::Surface> m_doublesur;
|
2014-08-09 21:37:51 +08:00
|
|
|
filters::TiledMode m_tiled;
|
|
|
|
};
|
|
|
|
|
2015-02-10 20:07:04 +08:00
|
|
|
class FullscreenPreviewCommand : public Command {
|
2012-01-06 06:45:03 +08:00
|
|
|
public:
|
2015-02-10 20:07:04 +08:00
|
|
|
FullscreenPreviewCommand();
|
|
|
|
Command* clone() const override { return new FullscreenPreviewCommand(*this); }
|
2012-01-06 06:45:03 +08:00
|
|
|
|
|
|
|
protected:
|
|
|
|
bool onEnabled(Context* context);
|
|
|
|
void onExecute(Context* context);
|
|
|
|
};
|
|
|
|
|
2015-02-10 20:07:04 +08:00
|
|
|
FullscreenPreviewCommand::FullscreenPreviewCommand()
|
|
|
|
: Command("FullscreenPreview",
|
|
|
|
"Fullscreen Preview",
|
2012-01-06 06:45:03 +08:00
|
|
|
CmdUIOnlyFlag)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-02-10 20:07:04 +08:00
|
|
|
bool FullscreenPreviewCommand::onEnabled(Context* context)
|
2012-01-06 06:45:03 +08:00
|
|
|
{
|
|
|
|
return context->checkFlags(ContextFlags::ActiveDocumentIsWritable |
|
|
|
|
ContextFlags::HasActiveSprite);
|
|
|
|
}
|
|
|
|
|
2013-08-06 08:20:19 +08:00
|
|
|
// Shows the sprite using the complete screen.
|
2015-02-10 20:07:04 +08:00
|
|
|
void FullscreenPreviewCommand::onExecute(Context* context)
|
2012-01-06 06:45:03 +08:00
|
|
|
{
|
|
|
|
Editor* editor = current_editor;
|
|
|
|
|
|
|
|
// Cancel operation if current editor does not have a sprite
|
2014-07-30 12:28:15 +08:00
|
|
|
if (!editor || !editor->sprite())
|
2012-01-06 06:45:03 +08:00
|
|
|
return;
|
|
|
|
|
2014-08-09 21:37:51 +08:00
|
|
|
PreviewWindow window(context, editor);
|
|
|
|
window.openWindowInForeground();
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
|
|
|
|
2015-02-10 20:07:04 +08:00
|
|
|
Command* CommandFactory::createFullscreenPreviewCommand()
|
2012-01-06 06:45:03 +08:00
|
|
|
{
|
2015-02-10 20:07:04 +08:00
|
|
|
return new FullscreenPreviewCommand;
|
2012-01-06 06:45:03 +08:00
|
|
|
}
|
2013-08-06 08:20:19 +08:00
|
|
|
|
|
|
|
} // namespace app
|