Change zoom scale to avoid similar zoom levels

- Renamed Editor::offset() with padding()
- Changed padding size (and added Editor::calcExtraPadding() function)
- Added Zoom::linearScale() and Zoom::fromLinearScale()
This commit is contained in:
David Capello 2015-08-04 12:26:58 -03:00
parent 43a3ee8bce
commit 3103f54131
6 changed files with 138 additions and 67 deletions

View File

@ -72,8 +72,8 @@ public:
gfx::Point scroll = view->getViewScroll();
m_oldMousePos = ui::get_mouse_position();
m_pos.x = -scroll.x + vp.x + editor->offsetX();
m_pos.y = -scroll.y + vp.y + editor->offsetY();
m_pos.x = -scroll.x + vp.x + editor->padding().x;
m_pos.y = -scroll.y + vp.y + editor->padding().y;
setFocusStop(true);
captureMouse();

View File

@ -153,8 +153,7 @@ Editor::Editor(Document* document, EditorFlags flags)
, m_brushPreview(this)
, m_quicktool(NULL)
, m_selectionMode(tools::SelectionMode::DEFAULT)
, m_offset_x(0)
, m_offset_y(0)
, m_padding(0, 0)
, m_mask_timer(100, this)
, m_offset_count(0)
, m_customizationDelegate(NULL)
@ -346,8 +345,8 @@ void Editor::setDefaultScroll()
setEditorScroll(
gfx::Point(
m_offset_x - vp.w/2 + (m_sprite->width()/2),
m_offset_y - vp.h/2 + (m_sprite->height()/2)), false);
m_padding.x - vp.w/2 + m_zoom.apply(m_sprite->width())/2,
m_padding.y - vp.h/2 + m_zoom.apply(m_sprite->height())/2), false);
}
// Sets the scroll position of the editor
@ -390,8 +389,8 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
gfx::Rect rc = m_sprite->bounds().createIntersection(spriteRectToDraw);
rc = m_zoom.apply(rc);
int dest_x = dx + m_offset_x + rc.x;
int dest_y = dy + m_offset_y + rc.y;
int dest_x = dx + m_padding.x + rc.x;
int dest_y = dy + m_padding.y + rc.y;
// Clip from graphics/screen
const gfx::Rect& clip = g->getClipBounds();
@ -536,8 +535,8 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& _rc)
gfx::Rect client = getClientBounds();
gfx::Rect spriteRect(
client.x + m_offset_x,
client.y + m_offset_y,
client.x + m_padding.x,
client.y + m_padding.y,
m_zoom.apply(m_sprite->width()),
m_zoom.apply(m_sprite->height()));
gfx::Rect enclosingRect = spriteRect;
@ -680,8 +679,8 @@ void Editor::drawMask(Graphics* g)
ASSERT(m_document->getMaskBoundaries());
int x = m_offset_x;
int y = m_offset_y;
int x = m_padding.x;
int y = m_padding.y;
for (const auto& seg : *m_document->getMaskBoundaries()) {
CheckedDrawMode checked(g, m_offset_count);
@ -954,8 +953,8 @@ gfx::Point Editor::screenToEditor(const gfx::Point& pt)
Point scroll = view->getViewScroll();
return gfx::Point(
m_zoom.remove(pt.x - vp.x + scroll.x - m_offset_x),
m_zoom.remove(pt.y - vp.y + scroll.y - m_offset_y));
m_zoom.remove(pt.x - vp.x + scroll.x - m_padding.x),
m_zoom.remove(pt.y - vp.y + scroll.y - m_padding.y));
}
Point Editor::editorToScreen(const gfx::Point& pt)
@ -965,8 +964,8 @@ Point Editor::editorToScreen(const gfx::Point& pt)
Point scroll = view->getViewScroll();
return Point(
(vp.x - scroll.x + m_offset_x + m_zoom.apply(pt.x)),
(vp.y - scroll.y + m_offset_y + m_zoom.apply(pt.y)));
(vp.x - scroll.x + m_padding.x + m_zoom.apply(pt.x)),
(vp.y - scroll.y + m_padding.y + m_zoom.apply(pt.y)));
}
Rect Editor::screenToEditor(const Rect& rc)
@ -1022,8 +1021,8 @@ void Editor::centerInSpritePoint(const gfx::Point& spritePos)
Rect vp = view->getViewportBounds();
gfx::Point scroll(
m_offset_x - (vp.w/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.x),
m_offset_y - (vp.h/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.y));
m_padding.x - (vp.w/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.x),
m_padding.y - (vp.h/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.y));
updateEditor();
setEditorScroll(scroll, false);
@ -1263,13 +1262,9 @@ void Editor::onPreferredSize(PreferredSizeEvent& ev)
gfx::Size sz(0, 0);
if (m_sprite) {
View* view = View::getView(this);
Rect vp = view->getViewportBounds();
int offset_x = std::max<int>(vp.w/2, vp.w - m_sprite->width()/2);
int offset_y = std::max<int>(vp.h/2, vp.h - m_sprite->height()/2);
sz.w = m_zoom.apply(m_sprite->width()) + offset_x*2;
sz.h = m_zoom.apply(m_sprite->height()) + offset_y*2;
gfx::Point padding = calcExtraPadding(m_zoom);
sz.w = m_zoom.apply(m_sprite->width()) + padding.x*2;
sz.h = m_zoom.apply(m_sprite->height()) + padding.y*2;
}
else {
sz.w = 4;
@ -1281,13 +1276,7 @@ void Editor::onPreferredSize(PreferredSizeEvent& ev)
void Editor::onResize(ui::ResizeEvent& ev)
{
Widget::onResize(ev);
View* view = View::getView(this);
if (view) {
Rect vp = view->getViewportBounds();
m_offset_x = std::max<int>(vp.w/2, vp.w - m_sprite->width()/2);
m_offset_y = std::max<int>(vp.h/2, vp.h - m_sprite->height()/2);
}
m_padding = calcExtraPadding(m_zoom);
}
void Editor::onPaint(ui::PaintEvent& ev)
@ -1412,13 +1401,20 @@ void Editor::setZoomAndCenterInMouse(Zoom zoom,
subpixelPos.x = (0.5 + screenPos.x - screenPos2.x) / m_zoom.scale();
subpixelPos.y = (0.5 + screenPos.y - screenPos2.y) / m_zoom.scale();
if (zoom.scale() > m_zoom.scale()) {
double t = 1.0 / zoom.scale();
if (subpixelPos.x >= 0.5-t && subpixelPos.x <= 0.5+t) subpixelPos.x = 0.5;
if (subpixelPos.y >= 0.5-t && subpixelPos.y <= 0.5+t) subpixelPos.y = 0.5;
}
ASSERT(subpixelPos.x >= -1.0 && subpixelPos.x <= 1.0);
ASSERT(subpixelPos.y >= -1.0 && subpixelPos.y <= 1.0);
}
gfx::Point padding = calcExtraPadding(zoom);
gfx::Point scrollPos(
m_offset_x - (screenPos.x-vp.x) + zoom.apply(spritePos.x+zoom.remove(1)/2) + int(zoom.apply(subpixelPos.x)),
m_offset_y - (screenPos.y-vp.y) + zoom.apply(spritePos.y+zoom.remove(1)/2) + int(zoom.apply(subpixelPos.y)));
padding.x - (screenPos.x-vp.x) + zoom.apply(spritePos.x+zoom.remove(1)/2) + int(zoom.apply(subpixelPos.x)),
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->getViewScroll())) {
bool blitValidRegion = (m_zoom == zoom);
@ -1574,4 +1570,18 @@ ImageBufferPtr Editor::getRenderImageBuffer()
return m_renderBuffer;
}
// static
gfx::Point Editor::calcExtraPadding(const Zoom& zoom)
{
View* view = View::getView(this);
if (view) {
Rect vp = view->getViewportBounds();
return gfx::Point(
std::max<int>(vp.w/2, vp.w - zoom.apply(m_sprite->width())),
std::max<int>(vp.h/2, vp.h - zoom.apply(m_sprite->height())));
}
else
return gfx::Point(0, 0);
}
} // namespace app

View File

@ -116,13 +116,9 @@ namespace app {
void setFrame(frame_t frame);
const render::Zoom& zoom() const { return m_zoom; }
int offsetX() const { return m_offset_x; }
int offsetY() const { return m_offset_y; }
const gfx::Point& padding() const { return m_padding; }
void setZoom(render::Zoom zoom) { m_zoom = zoom; }
void setOffsetX(int x) { m_offset_x = x; }
void setOffsetY(int y) { m_offset_y = y; }
void setDefaultScroll();
void setEditorScroll(const gfx::Point& scroll, bool blitValidRegion);
void setEditorZoom(render::Zoom zoom);
@ -238,6 +234,8 @@ namespace app {
// routine.
void drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy);
gfx::Point calcExtraPadding(const render::Zoom& zoom);
// Stack of states. The top element in the stack is the current state (m_state).
EditorStatesHistory m_statesHistory;
@ -264,9 +262,8 @@ namespace app {
tools::SelectionMode m_selectionMode;
bool m_autoSelectLayer;
// Offset for the sprite
int m_offset_x;
int m_offset_y;
// Extra space around the sprite.
gfx::Point m_padding;
// Marching ants stuff
ui::Timer m_mask_timer;

View File

@ -14,12 +14,17 @@
#include "app/app.h"
#include "app/ui/editor/editor.h"
#include "app/ui/status_bar.h"
#include "gfx/rect.h"
#include "doc/sprite.h"
#include "gfx/rect.h"
#include "she/display.h"
#include "ui/manager.h"
#include "ui/message.h"
#include "ui/system.h"
#include "ui/theme.h"
#include "ui/view.h"
#include <cmath>
namespace app {
using namespace ui;
@ -65,16 +70,17 @@ bool ZoomingState::onMouseUp(Editor* editor, MouseMessage* msg)
bool ZoomingState::onMouseMove(Editor* editor, MouseMessage* msg)
{
gfx::Point pt = (msg->position() - m_startPos);
render::Zoom zoom(1, 1);
double scale = m_startZoom.scale() + pt.x / 16.0;
if (scale < 1.0)
scale = 1.0 / -(scale-2.0);
zoom = render::Zoom::fromScale(scale);
int threshold = 8 * guiscale() * editor->getManager()->getDisplay()->scale();
editor->setZoomAndCenterInMouse(
zoom, m_startPos, Editor::ZoomBehavior::MOUSE);
if (m_moved || std::sqrt(pt.x*pt.x + pt.y*pt.y) > threshold) {
m_moved = true;
m_moved = true;
int newScale = m_startZoom.linearScale() + pt.x / threshold;
render::Zoom newZoom = render::Zoom::fromLinearScale(newScale);
editor->setZoomAndCenterInMouse(
newZoom, m_startPos, Editor::ZoomBehavior::MOUSE);
}
return true;
}

View File

@ -1,5 +1,5 @@
// Aseprite Render Library
// Copyright (c) 2001-2014 David Capello
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -12,35 +12,86 @@
namespace render {
static int scales[][2] = {
{ 1, 64 },
{ 1, 32 },
{ 1, 16 },
{ 1, 8 },
{ 1, 6 },
{ 1, 4 },
{ 1, 3 },
{ 1, 2 },
{ 1, 1 }, // 100%
{ 2, 1 },
{ 3, 1 },
{ 4, 1 },
{ 6, 1 },
{ 8, 1 },
{ 16, 1 },
{ 32, 1 },
{ 64, 1 },
};
static int scales_size = sizeof(scales) / sizeof(scales[0]);
void Zoom::in()
{
if (m_den > 1) {
m_den--;
}
else if (m_num < 64) {
m_num++;
int i = linearScale();
if (i < scales_size-1) {
++i;
m_num = scales[i][0];
m_den = scales[i][1];
}
}
void Zoom::out()
{
if (m_num > 1) {
m_num--;
int i = linearScale();
if (i > 0) {
--i;
m_num = scales[i][0];
m_den = scales[i][1];
}
else if (m_den < 32) {
m_den++;
}
int Zoom::linearScale()
{
for (int i=0; i<scales_size; ++i) {
// Exact match
if (scales[i][0] == m_num &&
scales[i][1] == m_den) {
return i;
}
}
return findClosestLinearScale(scale());
}
// static
Zoom Zoom::fromScale(double scale)
{
if (scale >= 1.0) {
return Zoom(int(scale), 1);
}
else {
return Zoom(1, int(1.0 / scale));
return fromLinearScale(findClosestLinearScale(scale));
}
// static
Zoom Zoom::fromLinearScale(int i)
{
i = MID(0, i, scales_size-1);
return Zoom(scales[i][0], scales[i][1]);
}
// static
int Zoom::findClosestLinearScale(double scale)
{
for (int i=0; i<scales_size-1; ++i) {
double min = double(scales[i ][0]) / double(scales[i ][1]) - 0.5;
double max = double(scales[i+1][0]) / double(scales[i+1][1]) - 0.5;
if (scale >= min && scale <= max)
return i;
}
if (scale < 1.0)
return 0;
else
return scales_size-1;
}
} // namespace render

View File

@ -1,5 +1,5 @@
// Aseprite Render Library
// Copyright (c) 2001-2014 David Capello
// Copyright (c) 2001-2015 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -44,6 +44,10 @@ namespace render {
void in();
void out();
// Returns an linear zoom scale. This position can be incremented
// or decremented to get a new zoom value.
int linearScale();
bool operator==(const Zoom& other) const {
return m_num == other.m_num && m_den == other.m_den;
}
@ -53,8 +57,11 @@ namespace render {
}
static Zoom fromScale(double scale);
static Zoom fromLinearScale(int i);
private:
static int findClosestLinearScale(double scale);
int m_num;
int m_den;
};