Add independent scroll/zoom values in preview window per document (fix #959)

This commit is contained in:
David Capello 2016-02-11 21:09:31 -03:00
parent ad9b7ce645
commit 7b8d9102e1
14 changed files with 198 additions and 66 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Aseprite -->
<!-- Copyright (C) 2014-2015 by David Capello -->
<!-- Copyright (C) 2014-2016 by David Capello -->
<preferences>
<types>
@ -275,6 +275,11 @@
<option id="type" type="app::SpriteSheetType" default="app::SpriteSheetType::Rows" />
<option id="bounds" type="gfx::Rect" default="gfx::Rect(0, 0, 16, 16)" />
</section>
<section id="preview" text="Preview">
<option id="zoom" type="double" default="1.0" />
<option id="scroll" type="gfx::Point" />
<option id="auto_scroll" type="bool" default="true" />
</section>
</document>
</preferences>

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -145,6 +145,28 @@ void set_config_bool(const char* section, const char* name, bool value)
g_configs.back()->setBoolValue(section, name, value);
}
Point get_config_point(const char* section, const char* name, const Point& point)
{
Point point2(point);
const char* value = get_config_string(section, name, "");
if (value) {
std::vector<std::string> parts;
base::split_string(value, parts, " ");
if (parts.size() == 2) {
point2.x = strtol(parts[0].c_str(), NULL, 10);
point2.y = strtol(parts[1].c_str(), NULL, 10);
}
}
return point2;
}
void set_config_point(const char* section, const char* name, const Point& point)
{
char buf[128];
sprintf(buf, "%d %d", point.x, point.y);
set_config_string(section, name, buf);
}
Rect get_config_rect(const char* section, const char* name, const Rect& rect)
{
Rect rect2(rect);

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -9,8 +9,9 @@
#define APP_INI_FILE_H_INCLUDED
#pragma once
#include "gfx/rect.h"
#include "app/color.h"
#include "gfx/point.h"
#include "gfx/rect.h"
namespace app {
@ -42,6 +43,9 @@ namespace app {
bool get_config_bool(const char* section, const char* name, bool value);
void set_config_bool(const char* section, const char* name, bool value);
gfx::Point get_config_point(const char* section, const char* name, const gfx::Point& point);
void set_config_point(const char* section, const char* name, const gfx::Point& point);
gfx::Rect get_config_rect(const char* section, const char* name, const gfx::Rect& rect);
void set_config_rect(const char* section, const char* name, const gfx::Rect& rect);
@ -77,6 +81,10 @@ namespace app {
return get_config_double(section, name, value);
}
inline gfx::Point get_config_value(const char* section, const char* name, const gfx::Point& value) {
return get_config_point(section, name, value);
}
inline gfx::Rect get_config_value(const char* section, const char* name, const gfx::Rect& value) {
return get_config_rect(section, name, value);
}
@ -110,6 +118,10 @@ namespace app {
set_config_double(section, name, value);
}
inline void set_config_value(const char* section, const char* name, const gfx::Point& value) {
set_config_point(section, name, value);
}
inline void set_config_value(const char* section, const char* name, const gfx::Rect& value) {
set_config_rect(section, name, value);
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -26,6 +26,7 @@
#include "filters/tiled_mode.h"
#include "gfx/rect.h"
#include "render/onionskin_position.h"
#include "render/zoom.h"
#include "pref.xml.h"

View File

@ -28,7 +28,6 @@
#include "app/ui/editor/editor_view.h"
#include "app/ui/keyboard_shortcuts.h"
#include "app/ui/main_window.h"
#include "app/ui/preview_editor.h"
#include "app/ui/status_bar.h"
#include "app/ui/workspace.h"
#include "app/ui_context.h"
@ -54,7 +53,10 @@ class AppEditor : public Editor,
public EditorObserver,
public EditorCustomizationDelegate {
public:
AppEditor(Document* document) : Editor(document) {
AppEditor(Document* document,
DocumentViewPreviewDelegate* previewDelegate)
: Editor(document)
, m_previewDelegate(previewDelegate) {
addObserver(this);
setCustomizationDelegate(this);
}
@ -66,29 +68,25 @@ public:
// EditorObserver implementation
void dispose() override {
PreviewEditorWindow* preview =
App::instance()->getMainWindow()->getPreviewEditor();
if (preview->relatedEditor() == this)
updatePreviewEditor(nullptr);
m_previewDelegate->onDisposeOtherEditor(this);
}
void onScrollChanged(Editor* editor) override {
updatePreviewEditor(this);
m_previewDelegate->onScrollOtherEditor(this);
if (isActive())
StatusBar::instance()->updateFromEditor(this);
}
void onAfterFrameChanged(Editor* editor) override {
updatePreviewEditor(this);
m_previewDelegate->onPreviewOtherEditor(this);
if (isActive())
set_current_palette(editor->sprite()->palette(editor->frame()), true);
}
void onAfterLayerChanged(Editor* editor) override {
updatePreviewEditor(this);
m_previewDelegate->onPreviewOtherEditor(this);
}
// EditorCustomizationDelegate implementation
@ -144,44 +142,28 @@ protected:
}
private:
void updatePreviewEditor(Editor* editor) {
App::instance()->getMainWindow()->getPreviewEditor()->updateUsingEditor(editor);
}
DocumentViewPreviewDelegate* m_previewDelegate;
};
class PreviewEditor : public Editor,
public EditorObserver {
class PreviewEditor : public Editor {
public:
PreviewEditor(Document* document)
: Editor(document, Editor::kShowOutside) // Don't show grid/mask in preview preview
{
addObserver(this);
}
~PreviewEditor() {
removeObserver(this);
}
private:
void onScrollChanged(Editor* editor) override {
if (hasCapture()) {
// TODO create a signal
App::instance()->getMainWindow()->getPreviewEditor()->uncheckCenterButton();
}
}
};
DocumentView::DocumentView(Document* document, Type type)
DocumentView::DocumentView(Document* document, Type type,
DocumentViewPreviewDelegate* previewDelegate)
: Box(VERTICAL)
, m_type(type)
, m_document(document)
, m_view(new EditorView(type == Normal ? EditorView::CurrentEditorMode:
EditorView::AlwaysSelected))
, m_previewDelegate(previewDelegate)
, m_editor((type == Normal ?
(Editor*)new AppEditor(document):
(Editor*)new PreviewEditor(document)))
(Editor*)new AppEditor(document, previewDelegate):
(Editor*)new PreviewEditor(document)))
{
addChild(m_view);
@ -215,7 +197,7 @@ TabIcon DocumentView::getTabIcon()
WorkspaceView* DocumentView::cloneWorkspaceView()
{
return new DocumentView(m_document, Normal);
return new DocumentView(m_document, Normal, m_previewDelegate);
}
void DocumentView::onWorkspaceViewSelected()

View File

@ -27,6 +27,14 @@ namespace app {
class Document;
class Editor;
class DocumentViewPreviewDelegate {
public:
virtual ~DocumentViewPreviewDelegate() { }
virtual void onScrollOtherEditor(Editor* editor) = 0;
virtual void onDisposeOtherEditor(Editor* editor) = 0;
virtual void onPreviewOtherEditor(Editor* editor) = 0;
};
class DocumentView : public ui::Box
, public TabView
, public doc::DocumentObserver
@ -38,7 +46,8 @@ namespace app {
Preview
};
DocumentView(Document* document, Type type);
DocumentView(Document* document, Type type,
DocumentViewPreviewDelegate* previewDelegate);
~DocumentView();
Document* getDocument() const { return m_document; }
@ -93,6 +102,7 @@ namespace app {
Type m_type;
Document* m_document;
ui::View* m_view;
DocumentViewPreviewDelegate* m_previewDelegate;
Editor* m_editor;
};

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -355,6 +355,14 @@ Site Editor::getSite() const
return site;
}
void Editor::setZoom(const render::Zoom& zoom)
{
if (m_zoom != zoom) {
m_zoom = zoom;
notifyZoomChanged();
}
}
void Editor::setDefaultScroll()
{
View* view = View::getView(this);
@ -1481,7 +1489,7 @@ void Editor::setZoomAndCenterInMouse(const Zoom& zoom,
padding.y - (screenPos.y-vp.y) + zoom.apply(spritePos.y+zoom.remove(1)/2) + int(zoom.apply(subpixelPos.y)));
if ((m_zoom != zoom) || (screenPos != view->viewScroll())) {
m_zoom = zoom;
setZoom(zoom);
updateEditor();
setEditorScroll(scrollPos);
@ -1576,6 +1584,11 @@ void Editor::notifyScrollChanged()
m_observers.notifyScrollChanged(this);
}
void Editor::notifyZoomChanged()
{
m_observers.notifyZoomChanged(this);
}
void Editor::play(bool playOnce)
{
ASSERT(m_state);

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -128,7 +128,7 @@ namespace app {
const render::Zoom& zoom() const { return m_zoom; }
const gfx::Point& padding() const { return m_padding; }
void setZoom(const render::Zoom& zoom) { m_zoom = zoom; }
void setZoom(const render::Zoom& zoom);
void setDefaultScroll();
void setEditorScroll(const gfx::Point& scroll);
void setEditorZoom(const render::Zoom& zoom);
@ -194,6 +194,7 @@ namespace app {
// Used by EditorView to notify changes in the view's scroll
// position.
void notifyScrollChanged();
void notifyZoomChanged();
// Animation control
void play(bool playOnce);

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -25,6 +25,7 @@ namespace app {
// Called when the scroll or zoom of the editor changes.
virtual void onScrollChanged(Editor* editor) { }
virtual void onZoomChanged(Editor* editor) { }
// Called when the current frame of the editor changes.
virtual void onBeforeFrameChanged(Editor* editor) { }

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -45,6 +45,11 @@ void EditorObservers::notifyScrollChanged(Editor* editor)
m_observers.notifyObservers(&EditorObserver::onScrollChanged, editor);
}
void EditorObservers::notifyZoomChanged(Editor* editor)
{
m_observers.notifyObservers(&EditorObserver::onZoomChanged, editor);
}
void EditorObservers::notifyBeforeFrameChanged(Editor* editor)
{
m_observers.notifyObservers(&EditorObserver::onBeforeFrameChanged, editor);

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -25,6 +25,7 @@ namespace app {
void notifyDestroyEditor(Editor* editor);
void notifyStateChanged(Editor* editor);
void notifyScrollChanged(Editor* editor);
void notifyZoomChanged(Editor* editor);
void notifyBeforeFrameChanged(Editor* editor);
void notifyAfterFrameChanged(Editor* editor);
void notifyBeforeLayerChanged(Editor* editor);

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -270,13 +270,26 @@ void PreviewEditorWindow::onWindowResize()
updateUsingEditor(view->getEditor());
}
bool PreviewEditorWindow::hasDocument() const
{
return (m_docView && m_docView->getDocument() != nullptr);
}
DocumentPreferences& PreviewEditorWindow::docPref()
{
Document* doc = (m_docView ? m_docView->getDocument(): nullptr);
return Preferences::instance().document(doc);
}
void PreviewEditorWindow::onCenterClicked()
{
if (m_centerButton->isSelected()) {
DocumentView* view = UIContext::instance()->activeView();
if (view)
updateUsingEditor(view->getEditor());
}
if (!m_relatedEditor || !hasDocument())
return;
bool autoScroll = m_centerButton->isSelected();
docPref().preview.autoScroll(autoScroll);
if (autoScroll)
updateUsingEditor(m_relatedEditor);
}
void PreviewEditorWindow::onPlayClicked()
@ -323,31 +336,38 @@ void PreviewEditorWindow::updateUsingEditor(Editor* editor)
if (!isVisible())
openWindow();
gfx::Rect visibleBounds = editor->getVisibleSpriteBounds();
gfx::Point centerPoint = visibleBounds.center();
bool center = (m_centerButton->isSelected());
// Document preferences used to store the preferred zoom/scroll point
auto& docPref = Preferences::instance().document(document);
bool autoScroll = docPref.preview.autoScroll();
// Set the same location as in the given editor.
if (!miniEditor || miniEditor->document() != document) {
destroyDocView();
m_docView = new DocumentView(document, DocumentView::Preview);
m_docView = new DocumentView(document, DocumentView::Preview, this);
addChild(m_docView);
miniEditor = m_docView->getEditor();
miniEditor->setZoom(render::Zoom(1, 1));
miniEditor->setZoom(render::Zoom::fromScale(docPref.preview.zoom()));
miniEditor->setLayer(editor->layer());
miniEditor->setFrame(editor->frame());
miniEditor->setState(EditorStatePtr(new NavigateState));
miniEditor->setAnimationSpeedMultiplier(m_aniSpeed);
miniEditor->addObserver(this);
layout();
center = true;
if (!autoScroll)
miniEditor->setEditorScroll(docPref.preview.scroll());
}
if (center)
m_centerButton->setSelected(autoScroll);
if (autoScroll) {
gfx::Point centerPoint = editor->getVisibleSpriteBounds().center();
miniEditor->centerInSpritePoint(centerPoint);
saveScrollPref();
}
if (!m_playButton->isPlaying()) {
miniEditor->stop();
miniEditor->setLayer(editor->layer());
@ -370,8 +390,10 @@ void PreviewEditorWindow::updateUsingEditor(Editor* editor)
void PreviewEditorWindow::uncheckCenterButton()
{
if (m_centerButton->isSelected())
if (m_centerButton->isSelected()) {
m_centerButton->setSelected(false);
onCenterClicked();
}
}
void PreviewEditorWindow::onStateChanged(Editor* editor)
@ -386,6 +408,48 @@ void PreviewEditorWindow::onStateChanged(Editor* editor)
}
}
void PreviewEditorWindow::onScrollChanged(Editor* miniEditor)
{
if (miniEditor->hasCapture()) {
saveScrollPref();
uncheckCenterButton();
}
}
void PreviewEditorWindow::onZoomChanged(Editor* miniEditor)
{
saveScrollPref();
}
void PreviewEditorWindow::saveScrollPref()
{
ASSERT(m_docView);
if (!m_docView)
return;
Editor* miniEditor = m_docView->getEditor();
ASSERT(miniEditor);
docPref().preview.scroll(View::getView(miniEditor)->viewScroll());
docPref().preview.zoom(miniEditor->zoom().scale());
}
void PreviewEditorWindow::onScrollOtherEditor(Editor* editor)
{
updateUsingEditor(editor);
}
void PreviewEditorWindow::onDisposeOtherEditor(Editor* editor)
{
if (m_relatedEditor == editor)
updateUsingEditor(nullptr);
}
void PreviewEditorWindow::onPreviewOtherEditor(Editor* editor)
{
updateUsingEditor(editor);
}
void PreviewEditorWindow::hideWindow()
{
destroyDocView();

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -12,6 +12,7 @@
#include "app/ui/document_view.h"
#include "app/ui/editor/editor_observer.h"
#include "doc/frame.h"
#include "app/pref/preferences.h"
#include "ui/window.h"
namespace app {
@ -19,7 +20,8 @@ namespace app {
class MiniPlayButton;
class PreviewEditorWindow : public ui::Window
, public EditorObserver {
, public EditorObserver
, public DocumentViewPreviewDelegate {
public:
PreviewEditorWindow();
~PreviewEditorWindow();
@ -28,12 +30,18 @@ namespace app {
void setPreviewEnabled(bool state);
void updateUsingEditor(Editor* editor);
void uncheckCenterButton();
Editor* relatedEditor() const { return m_relatedEditor; }
// EditorObserver impl
void onStateChanged(Editor* editor) override;
void onScrollChanged(Editor* editor) override;
void onZoomChanged(Editor* editor) override;
// DocumentViewPreviewDelegate impl
void onScrollOtherEditor(Editor* editor) override;
void onDisposeOtherEditor(Editor* editor) override;
void onPreviewOtherEditor(Editor* editor) override;
protected:
bool onProcessMessage(ui::Message* msg) override;
@ -41,11 +49,15 @@ namespace app {
void onWindowResize() override;
private:
void uncheckCenterButton();
bool hasDocument() const;
DocumentPreferences& docPref();
void onCenterClicked();
void onPlayClicked();
void onPopupSpeed();
void hideWindow();
void destroyDocView();
void saveScrollPref();
bool m_isEnabled;
DocumentView* m_docView;

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2001-2015 David Capello
// Copyright (C) 2001-2016 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
@ -194,7 +194,10 @@ void UIContext::onAddDocument(doc::Document* doc)
return;
// Add a new view for this document
DocumentView* view = new DocumentView(m_lastSelectedDoc, DocumentView::Normal);
DocumentView* view = new DocumentView(
m_lastSelectedDoc,
DocumentView::Normal,
App::instance()->getMainWindow()->getPreviewEditor());
// Add a tab with the new view for the document
App::instance()->getMainWindow()->getWorkspace()->addView(view);