mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-28 00:35:30 +00:00
Add zoom out (related to issue #33)
Before the zoom was handle as a bits shift (scaled = value << zoom), now the zoom is a fraction (scaled = value * zoom.num / zoom.den). Changes: * Add Zoom class to apply/remove zoom factor * Split merge_zoomed_image template function into merge_zoomed_image_scale_down and merge_zoomed_image_scale_up to handle the special case where zoom.num/zoom.den < 1.0
This commit is contained in:
parent
17b0bee0ae
commit
4fc28d5639
@ -259,4 +259,5 @@ add_library(app-lib
|
||||
webserver.cpp
|
||||
widget_loader.cpp
|
||||
xml_document.cpp
|
||||
xml_exception.cpp)
|
||||
xml_exception.cpp
|
||||
zoom.cpp)
|
||||
|
@ -99,13 +99,13 @@ void MoveMaskCommand::onExecute(Context* context)
|
||||
pixels = gridBounds.h;
|
||||
break;
|
||||
case ZoomedPixel:
|
||||
pixels = 1 << current_editor->zoom();
|
||||
pixels = current_editor->zoom().apply(1);
|
||||
break;
|
||||
case ZoomedTileWidth:
|
||||
pixels = gridBounds.w << current_editor->zoom();
|
||||
pixels = current_editor->zoom().apply(gridBounds.w);
|
||||
break;
|
||||
case ZoomedTileHeight:
|
||||
pixels = gridBounds.h << current_editor->zoom();
|
||||
pixels = current_editor->zoom().apply(gridBounds.h);
|
||||
break;
|
||||
case ViewportWidth:
|
||||
pixels = vp.h;
|
||||
|
@ -63,7 +63,8 @@ public:
|
||||
, m_pal(m_sprite->getPalette(editor->frame()))
|
||||
, m_index_bg_color(-1)
|
||||
, m_doublebuf(Image::create(IMAGE_RGB, ui::display_w(), ui::display_h()))
|
||||
, m_doublesur(she::instance()->createRgbaSurface(ui::display_w(), ui::display_h())) {
|
||||
, m_doublesur(she::instance()->createRgbaSurface(ui::display_w(), ui::display_h()))
|
||||
, m_zoom(editor->zoom()) {
|
||||
// Do not use DocumentWriter (do not lock the document) because we
|
||||
// will call other sub-commands (e.g. previous frame, next frame,
|
||||
// etc.).
|
||||
@ -83,7 +84,6 @@ public:
|
||||
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_zoom = editor->zoom();
|
||||
|
||||
setFocusStop(true);
|
||||
captureMouse();
|
||||
@ -193,14 +193,14 @@ protected:
|
||||
m_render.reset(
|
||||
renderEngine.renderSprite(
|
||||
0, 0, m_sprite->width(), m_sprite->height(),
|
||||
m_editor->frame(), 0, false, false));
|
||||
m_editor->frame(), Zoom(1, 1), false, false));
|
||||
}
|
||||
|
||||
int x, y, w, h, u, v;
|
||||
x = m_pos.x + ((m_delta.x >> m_zoom) << m_zoom);
|
||||
y = m_pos.y + ((m_delta.y >> m_zoom) << m_zoom);
|
||||
w = (m_sprite->width()<<m_zoom);
|
||||
h = (m_sprite->height()<<m_zoom);
|
||||
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());
|
||||
|
||||
if (m_tiled & TILED_X_AXIS) x = SGN(x) * (ABS(x)%w);
|
||||
if (m_tiled & TILED_Y_AXIS) y = SGN(y) * (ABS(y)%h);
|
||||
@ -243,7 +243,7 @@ private:
|
||||
gfx::Point m_pos;
|
||||
gfx::Point m_oldMousePos;
|
||||
gfx::Point m_delta;
|
||||
int m_zoom;
|
||||
Zoom m_zoom;
|
||||
int m_index_bg_color;
|
||||
base::UniquePtr<Image> m_render;
|
||||
base::UniquePtr<Image> m_doublebuf;
|
||||
|
@ -117,13 +117,13 @@ void ScrollCommand::onExecute(Context* context)
|
||||
pixels = gridBounds.h;
|
||||
break;
|
||||
case ZoomedPixel:
|
||||
pixels = 1 << current_editor->zoom();
|
||||
pixels = current_editor->zoom().apply(1);
|
||||
break;
|
||||
case ZoomedTileWidth:
|
||||
pixels = gridBounds.w << current_editor->zoom();
|
||||
pixels = current_editor->zoom().apply(gridBounds.w);
|
||||
break;
|
||||
case ZoomedTileHeight:
|
||||
pixels = gridBounds.h << current_editor->zoom();
|
||||
pixels = current_editor->zoom().apply(gridBounds.h);
|
||||
break;
|
||||
case ViewportWidth:
|
||||
pixels = vp.h;
|
||||
|
@ -74,25 +74,23 @@ bool ZoomCommand::onEnabled(Context* context)
|
||||
|
||||
void ZoomCommand::onExecute(Context* context)
|
||||
{
|
||||
int zoom = current_editor->zoom();
|
||||
Zoom zoom = current_editor->zoom();
|
||||
|
||||
switch (m_action) {
|
||||
case In:
|
||||
if (zoom < 5)
|
||||
++zoom;
|
||||
zoom.in();
|
||||
break;
|
||||
case Out:
|
||||
if (zoom > 0)
|
||||
--zoom;
|
||||
zoom.out();
|
||||
break;
|
||||
case Set:
|
||||
switch (m_percentage) {
|
||||
case 3200: zoom = 5; break;
|
||||
case 1600: zoom = 4; break;
|
||||
case 800: zoom = 3; break;
|
||||
case 400: zoom = 2; break;
|
||||
case 200: zoom = 1; break;
|
||||
default: zoom = 0; break;
|
||||
case 3200: zoom = Zoom(32, 1); break;
|
||||
case 1600: zoom = Zoom(16, 1); break;
|
||||
case 800: zoom = Zoom(8, 1); break;
|
||||
case 400: zoom = Zoom(4, 1); break;
|
||||
case 200: zoom = Zoom(2, 1); break;
|
||||
default: zoom = Zoom(1, 1); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -257,8 +257,8 @@ void FilterManagerImpl::flush()
|
||||
m_x+m_offset_x,
|
||||
m_y+m_offset_y+m_row-1)),
|
||||
gfx::Size(
|
||||
(m_w << editor->zoom()),
|
||||
(1 << editor->zoom())));
|
||||
editor->zoom().apply(m_w),
|
||||
editor->zoom().apply(1)));
|
||||
|
||||
gfx::Region reg1(rect);
|
||||
gfx::Region reg2;
|
||||
|
@ -85,7 +85,7 @@ private:
|
||||
|
||||
base::UniquePtr<Image> image(renderEngine.renderSprite(
|
||||
0, 0, sprite->width(), sprite->height(),
|
||||
FrameNumber(0), 0, true, false));
|
||||
FrameNumber(0), Zoom(1, 1), true, false));
|
||||
|
||||
// Calculate the thumbnail size
|
||||
int thumb_w = MAX_THUMBNAIL_SIZE * image->width() / MAX(image->width(), image->height());
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
#include "app/settings/selection_mode.h"
|
||||
#include "app/tools/trace_policy.h"
|
||||
#include "app/zoom.h"
|
||||
#include "doc/frame_number.h"
|
||||
#include "filters/tiled_mode.h"
|
||||
#include "gfx/point.h"
|
||||
@ -104,6 +105,9 @@ namespace app {
|
||||
// Gets mask X,Y origin coordinates
|
||||
virtual gfx::Point getMaskOrigin() = 0;
|
||||
|
||||
// Returns the zoom
|
||||
virtual const Zoom& zoom() = 0;
|
||||
|
||||
// Return the mouse button which start the tool-loop. It can be used
|
||||
// by some tools that instead of using the primary/secondary color
|
||||
// uses the pressed button for different behavior (like selection
|
||||
|
@ -213,7 +213,7 @@ void ToolLoopManager::doLoopStep(bool last_step)
|
||||
|
||||
// Calculate the area to be updated in all document observers.
|
||||
Region& dirty_area = m_toolLoop->getDirtyArea();
|
||||
calculateDirtyArea(m_toolLoop, points_to_interwine, dirty_area);
|
||||
calculateDirtyArea(points_to_interwine, dirty_area);
|
||||
|
||||
if (m_toolLoop->getTracePolicy() == TracePolicyLast) {
|
||||
Region prev_dirty_area = dirty_area;
|
||||
@ -235,7 +235,7 @@ void ToolLoopManager::snapToGrid(Point& point)
|
||||
m_toolLoop->getDocumentSettings()->snapToGrid(point);
|
||||
}
|
||||
|
||||
void ToolLoopManager::calculateDirtyArea(ToolLoop* loop, const Points& points, Region& dirty_area)
|
||||
void ToolLoopManager::calculateDirtyArea(const Points& points, Region& dirty_area)
|
||||
{
|
||||
dirty_area.clear();
|
||||
|
||||
@ -245,21 +245,21 @@ void ToolLoopManager::calculateDirtyArea(ToolLoop* loop, const Points& points, R
|
||||
|
||||
// Expand the dirty-area with the pen width
|
||||
Rect r1, r2;
|
||||
loop->getPointShape()->getModifiedArea(loop, minpt.x, minpt.y, r1);
|
||||
loop->getPointShape()->getModifiedArea(loop, maxpt.x, maxpt.y, r2);
|
||||
m_toolLoop->getPointShape()->getModifiedArea(m_toolLoop, minpt.x, minpt.y, r1);
|
||||
m_toolLoop->getPointShape()->getModifiedArea(m_toolLoop, maxpt.x, maxpt.y, r2);
|
||||
|
||||
dirty_area.createUnion(dirty_area, Region(r1.createUnion(r2)));
|
||||
}
|
||||
|
||||
// Apply offset mode
|
||||
Point offset(loop->getOffset());
|
||||
Point offset(m_toolLoop->getOffset());
|
||||
dirty_area.offset(-offset);
|
||||
|
||||
// Apply tiled mode
|
||||
TiledMode tiledMode = loop->getDocumentSettings()->getTiledMode();
|
||||
TiledMode tiledMode = m_toolLoop->getDocumentSettings()->getTiledMode();
|
||||
if (tiledMode != TILED_NONE) {
|
||||
int w = loop->sprite()->width();
|
||||
int h = loop->sprite()->height();
|
||||
int w = m_toolLoop->sprite()->width();
|
||||
int h = m_toolLoop->sprite()->height();
|
||||
Region sprite_area(Rect(0, 0, w, h));
|
||||
Region outside;
|
||||
outside.createSubtraction(dirty_area, sprite_area);
|
||||
@ -312,6 +312,11 @@ void ToolLoopManager::calculateMinMax(const Points& points, Point& minpt, Point&
|
||||
maxpt.x = MAX(maxpt.x, points[c].x);
|
||||
maxpt.y = MAX(maxpt.y, points[c].y);
|
||||
}
|
||||
|
||||
if (m_toolLoop->zoom().scale() < 1.0) {
|
||||
maxpt.x += m_toolLoop->zoom().remove(1);
|
||||
maxpt.y += m_toolLoop->zoom().remove(1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace tools
|
||||
|
@ -103,13 +103,13 @@ namespace app {
|
||||
void doLoopStep(bool last_step);
|
||||
void snapToGrid(gfx::Point& point);
|
||||
|
||||
static void calculateDirtyArea(ToolLoop* loop,
|
||||
const Points& points,
|
||||
gfx::Region& dirty_area);
|
||||
void calculateDirtyArea(
|
||||
const Points& points,
|
||||
gfx::Region& dirty_area);
|
||||
|
||||
static void calculateMinMax(const Points& points,
|
||||
gfx::Point& minpt,
|
||||
gfx::Point& maxpt);
|
||||
void calculateMinMax(const Points& points,
|
||||
gfx::Point& minpt,
|
||||
gfx::Point& maxpt);
|
||||
|
||||
ToolLoop* m_toolLoop;
|
||||
Points m_points;
|
||||
|
@ -55,7 +55,7 @@ namespace app {
|
||||
using namespace ui;
|
||||
|
||||
// Returns true if the cursor of the editor needs subpixel movement.
|
||||
#define IS_SUBPIXEL(editor) ((editor)->m_zoom >= 2)
|
||||
#define IS_SUBPIXEL(editor) ((editor)->m_zoom.scale() >= 4.0)
|
||||
|
||||
// Maximum quantity of colors to save pixels overlapped by the cursor.
|
||||
#define MAX_SAVED 4096
|
||||
@ -514,25 +514,22 @@ static void trace_thickcross_pixels(ui::Graphics* g, Editor* editor,
|
||||
0, 0, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 0, 0,
|
||||
};
|
||||
gfx::Point out;
|
||||
gfx::Point out, outpt = editor->editorToScreen(pt);
|
||||
int u, v;
|
||||
int zoom = editor->zoom();
|
||||
int size = editor->zoom().apply(thickness/2);
|
||||
int size2 = editor->zoom().apply(thickness);
|
||||
if (size2 == 0) size2 = 1;
|
||||
|
||||
for (v=0; v<6; v++) {
|
||||
for (u=0; u<6; u++) {
|
||||
if (cursor_cross[v*6+u]) {
|
||||
out = editor->editorToScreen(pt);
|
||||
if (!cursor_cross[v*6+u])
|
||||
continue;
|
||||
|
||||
out.x += ((u<3) ?
|
||||
u-((thickness>>1)<<zoom)-3:
|
||||
u-((thickness>>1)<<zoom)-3+(thickness<<zoom));
|
||||
out = outpt;
|
||||
out.x += ((u<3) ? u-size-3: u-size-3+size2);
|
||||
out.y += ((v<3) ? v-size-3: v-size-3+size2);
|
||||
|
||||
out.y += ((v<3)?
|
||||
v-((thickness>>1)<<zoom)-3:
|
||||
v-((thickness>>1)<<zoom)-3+(thickness<<zoom));
|
||||
|
||||
pixelDelegate(g, out, color);
|
||||
}
|
||||
pixelDelegate(g, out, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ using namespace ui;
|
||||
|
||||
class EditorPreRenderImpl : public EditorPreRender {
|
||||
public:
|
||||
EditorPreRenderImpl(Editor* editor, Image* image, const Point& offset, int zoom)
|
||||
EditorPreRenderImpl(Editor* editor, Image* image, const Point& offset, Zoom zoom)
|
||||
: m_editor(editor)
|
||||
, m_image(image)
|
||||
, m_offset(offset)
|
||||
@ -92,17 +92,17 @@ public:
|
||||
void fillRect(const gfx::Rect& rect, uint32_t rgbaColor, int opacity) override
|
||||
{
|
||||
blend_rect(m_image,
|
||||
m_offset.x + (rect.x << m_zoom),
|
||||
m_offset.y + (rect.y << m_zoom),
|
||||
m_offset.x + ((rect.x+rect.w) << m_zoom) - 1,
|
||||
m_offset.y + ((rect.y+rect.h) << m_zoom) - 1, rgbaColor, opacity);
|
||||
m_offset.x + m_zoom.apply(rect.x),
|
||||
m_offset.y + m_zoom.apply(rect.y),
|
||||
m_offset.x + m_zoom.apply(rect.x+rect.w) - 1,
|
||||
m_offset.y + m_zoom.apply(rect.y+rect.h) - 1, rgbaColor, opacity);
|
||||
}
|
||||
|
||||
private:
|
||||
Editor* m_editor;
|
||||
Image* m_image;
|
||||
Point m_offset;
|
||||
int m_zoom;
|
||||
Zoom m_zoom;
|
||||
};
|
||||
|
||||
class EditorPostRenderImpl : public EditorPostRender {
|
||||
@ -145,7 +145,7 @@ Editor::Editor(Document* document, EditorFlags flags)
|
||||
, m_sprite(m_document->sprite())
|
||||
, m_layer(m_sprite->folder()->getFirstLayer())
|
||||
, m_frame(FrameNumber(0))
|
||||
, m_zoom(0)
|
||||
, m_zoom(1, 1)
|
||||
, m_cursorThick(0)
|
||||
, m_cursorScreen(0, 0)
|
||||
, m_cursorEditor(0, 0)
|
||||
@ -324,7 +324,7 @@ void Editor::setEditorScroll(const gfx::Point& scroll, bool blit_valid_rgn)
|
||||
drawBrushPreview(m_cursorScreen);
|
||||
}
|
||||
|
||||
void Editor::setEditorZoom(int zoom)
|
||||
void Editor::setEditorZoom(Zoom zoom)
|
||||
{
|
||||
setZoomAndCenterInMouse(zoom,
|
||||
ui::get_mouse_position(), Editor::kCofiguredZoomBehavior);
|
||||
@ -338,12 +338,12 @@ void Editor::updateEditor()
|
||||
void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, int dx, int dy)
|
||||
{
|
||||
// Output information
|
||||
int source_x = rc.x << m_zoom;
|
||||
int source_y = rc.y << m_zoom;
|
||||
int source_x = m_zoom.apply(rc.x);
|
||||
int source_y = m_zoom.apply(rc.y);
|
||||
int dest_x = dx + m_offset_x + source_x;
|
||||
int dest_y = dy + m_offset_y + source_y;
|
||||
int width = rc.w << m_zoom;
|
||||
int height = rc.h << m_zoom;
|
||||
int width = m_zoom.apply(rc.w);
|
||||
int height = m_zoom.apply(rc.h);
|
||||
|
||||
// Clip from graphics/screen
|
||||
const gfx::Rect& clip = g->getClipBounds();
|
||||
@ -375,11 +375,11 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, in
|
||||
dest_y -= source_y;
|
||||
source_y = 0;
|
||||
}
|
||||
if (source_x+width > (m_sprite->width() << m_zoom)) {
|
||||
width = (m_sprite->width() << m_zoom) - source_x;
|
||||
if (source_x+width > m_zoom.apply(m_sprite->width())) {
|
||||
width = m_zoom.apply(m_sprite->width()) - source_x;
|
||||
}
|
||||
if (source_y+height > (m_sprite->height() << m_zoom)) {
|
||||
height = (m_sprite->height() << m_zoom) - source_y;
|
||||
if (source_y+height > m_zoom.apply(m_sprite->height())) {
|
||||
height = m_zoom.apply(m_sprite->height()) - source_y;
|
||||
}
|
||||
|
||||
// Draw the sprite
|
||||
@ -402,7 +402,7 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc, in
|
||||
// Pre-render decorator.
|
||||
if ((m_flags & kShowDecorators) && m_decorator) {
|
||||
EditorPreRenderImpl preRender(this, rendered,
|
||||
Point(-source_x, -source_y), m_zoom);
|
||||
Point(-source_x, -source_y), m_zoom);
|
||||
m_decorator->preRenderDecorator(&preRender);
|
||||
}
|
||||
|
||||
@ -423,8 +423,8 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc)
|
||||
gfx::Rect spriteRect(
|
||||
client.x + m_offset_x,
|
||||
client.y + m_offset_y,
|
||||
(m_sprite->width() << m_zoom),
|
||||
(m_sprite->height() << m_zoom));
|
||||
m_zoom.apply(m_sprite->width()),
|
||||
m_zoom.apply(m_sprite->height()));
|
||||
gfx::Rect enclosingRect = spriteRect;
|
||||
|
||||
// Draw the main sprite at the center.
|
||||
@ -473,7 +473,7 @@ void Editor::drawSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& rc)
|
||||
}
|
||||
|
||||
// Draw the pixel grid
|
||||
if ((m_zoom > 1) && docSettings->getPixelGridVisible()) {
|
||||
if ((m_zoom.scale() > 1.0) && docSettings->getPixelGridVisible()) {
|
||||
drawGrid(g, enclosingRect, Rect(0, 0, 1, 1), docSettings->getPixelGridColor());
|
||||
}
|
||||
|
||||
@ -544,10 +544,10 @@ void Editor::drawMask(Graphics* g)
|
||||
CheckedDrawMode checked(g, m_offset_count);
|
||||
|
||||
for (int c=0; c<nseg; ++c, ++seg) {
|
||||
x1 = seg->x1 << m_zoom;
|
||||
y1 = seg->y1 << m_zoom;
|
||||
x2 = seg->x2 << m_zoom;
|
||||
y2 = seg->y2 << m_zoom;
|
||||
x1 = m_zoom.apply(seg->x1);
|
||||
y1 = m_zoom.apply(seg->y1);
|
||||
x2 = m_zoom.apply(seg->x2);
|
||||
y2 = m_zoom.apply(seg->y2);
|
||||
|
||||
#if 1 // Bounds inside mask
|
||||
if (!seg->open)
|
||||
@ -863,8 +863,8 @@ gfx::Point Editor::screenToEditor(const gfx::Point& pt)
|
||||
Point scroll = view->getViewScroll();
|
||||
|
||||
return gfx::Point(
|
||||
(pt.x - vp.x + scroll.x - m_offset_x) >> m_zoom,
|
||||
(pt.y - vp.y + scroll.y - m_offset_y) >> m_zoom);
|
||||
m_zoom.remove(pt.x - vp.x + scroll.x - m_offset_x),
|
||||
m_zoom.remove(pt.y - vp.y + scroll.y - m_offset_y));
|
||||
}
|
||||
|
||||
Point Editor::editorToScreen(const gfx::Point& pt)
|
||||
@ -874,8 +874,8 @@ Point Editor::editorToScreen(const gfx::Point& pt)
|
||||
Point scroll = view->getViewScroll();
|
||||
|
||||
return Point(
|
||||
(vp.x - scroll.x + m_offset_x + (pt.x << m_zoom)),
|
||||
(vp.y - scroll.y + m_offset_y + (pt.y << m_zoom)));
|
||||
(vp.x - scroll.x + m_offset_x + m_zoom.apply(pt.x)),
|
||||
(vp.y - scroll.y + m_offset_y + m_zoom.apply(pt.y)));
|
||||
}
|
||||
|
||||
Rect Editor::screenToEditor(const Rect& rc)
|
||||
@ -968,8 +968,8 @@ void Editor::centerInSpritePoint(const gfx::Point& spritePos)
|
||||
hideDrawingCursor();
|
||||
|
||||
gfx::Point scroll(
|
||||
m_offset_x - (vp.w/2) + ((1<<m_zoom)>>1) + (spritePos.x << m_zoom),
|
||||
m_offset_y - (vp.h/2) + ((1<<m_zoom)>>1) + (spritePos.y << m_zoom));
|
||||
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));
|
||||
|
||||
updateEditor();
|
||||
setEditorScroll(scroll, false);
|
||||
@ -1212,8 +1212,8 @@ void Editor::onPreferredSize(PreferredSizeEvent& ev)
|
||||
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);
|
||||
|
||||
sz.w = (m_sprite->width() << m_zoom) + m_offset_x*2;
|
||||
sz.h = (m_sprite->height() << m_zoom) + m_offset_y*2;
|
||||
sz.w = m_zoom.apply(m_sprite->width()) + m_offset_x*2;
|
||||
sz.h = m_zoom.apply(m_sprite->height()) + m_offset_y*2;
|
||||
}
|
||||
else {
|
||||
sz.w = 4;
|
||||
@ -1311,7 +1311,7 @@ bool Editor::isInsideSelection()
|
||||
m_document->mask()->containsPoint(spritePos.x, spritePos.y);
|
||||
}
|
||||
|
||||
void Editor::setZoomAndCenterInMouse(int zoom,
|
||||
void Editor::setZoomAndCenterInMouse(Zoom zoom,
|
||||
const gfx::Point& mousePos, ZoomBehavior zoomBehavior)
|
||||
{
|
||||
View* view = View::getView(this);
|
||||
@ -1343,8 +1343,8 @@ void Editor::setZoomAndCenterInMouse(int zoom,
|
||||
mid.y = mousePos.y;
|
||||
}
|
||||
|
||||
spritePos.x = m_offset_x - (mid.x - vp.x) + ((1<<zoom)>>1) + (spritePos.x << zoom);
|
||||
spritePos.y = m_offset_y - (mid.y - vp.y) + ((1<<zoom)>>1) + (spritePos.y << zoom);
|
||||
spritePos.x = m_offset_x - (mid.x - vp.x) + (zoom.apply(1)/2) + zoom.apply(spritePos.x);
|
||||
spritePos.y = m_offset_y - (mid.y - vp.y) + (zoom.apply(1)/2) + zoom.apply(spritePos.y);
|
||||
|
||||
if ((m_zoom != zoom) || (m_cursorEditor != mid)) {
|
||||
bool blit_valid_rgn = (m_zoom == zoom);
|
||||
|
@ -27,16 +27,14 @@
|
||||
#include "app/ui/editor/editor_observers.h"
|
||||
#include "app/ui/editor/editor_state.h"
|
||||
#include "app/ui/editor/editor_states_history.h"
|
||||
#include "app/zoom.h"
|
||||
#include "base/connection.h"
|
||||
#include "gfx/fwd.h"
|
||||
#include "doc/frame_number.h"
|
||||
#include "gfx/fwd.h"
|
||||
#include "ui/base.h"
|
||||
#include "ui/timer.h"
|
||||
#include "ui/widget.h"
|
||||
|
||||
#define MIN_ZOOM 0
|
||||
#define MAX_ZOOM 5
|
||||
|
||||
namespace doc {
|
||||
class Sprite;
|
||||
class Layer;
|
||||
@ -122,18 +120,18 @@ namespace app {
|
||||
void setLayer(const Layer* layer);
|
||||
void setFrame(FrameNumber frame);
|
||||
|
||||
int zoom() const { return m_zoom; }
|
||||
const Zoom& zoom() const { return m_zoom; }
|
||||
int offsetX() const { return m_offset_x; }
|
||||
int offsetY() const { return m_offset_y; }
|
||||
int cursorThick() { return m_cursorThick; }
|
||||
|
||||
void setZoom(int zoom) { m_zoom = zoom; }
|
||||
void setZoom(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 blit_valid_rgn);
|
||||
void setEditorZoom(int zoom);
|
||||
void setEditorZoom(Zoom zoom);
|
||||
|
||||
// Updates the Editor's view.
|
||||
void updateEditor();
|
||||
@ -187,7 +185,7 @@ namespace app {
|
||||
// Returns true if the cursor is inside the active mask/selection.
|
||||
bool isInsideSelection();
|
||||
|
||||
void setZoomAndCenterInMouse(int zoom,
|
||||
void setZoomAndCenterInMouse(Zoom zoom,
|
||||
const gfx::Point& mousePos, ZoomBehavior zoomBehavior);
|
||||
|
||||
void pasteImage(const Image* image, const gfx::Point& pos);
|
||||
@ -260,7 +258,7 @@ namespace app {
|
||||
Sprite* m_sprite; // Active sprite in the editor
|
||||
Layer* m_layer; // Active layer in the editor
|
||||
FrameNumber m_frame; // Active frame in the editor
|
||||
int m_zoom; // Zoom in the editor
|
||||
Zoom m_zoom; // Zoom in the editor
|
||||
|
||||
// Drawing cursor
|
||||
int m_cursorThick;
|
||||
|
@ -179,10 +179,10 @@ void SelectBoxState::preRenderDecorator(EditorPreRender* render)
|
||||
void SelectBoxState::postRenderDecorator(EditorPostRender* render)
|
||||
{
|
||||
Editor* editor = render->getEditor();
|
||||
int zoom = editor->zoom();
|
||||
Zoom zoom = editor->zoom();
|
||||
gfx::Rect vp = View::getView(editor)->getViewportBounds();
|
||||
vp.w += 1<<zoom;
|
||||
vp.h += 1<<zoom;
|
||||
vp.w += zoom.apply(1);
|
||||
vp.h += zoom.apply(1);
|
||||
vp = editor->screenToEditor(vp);
|
||||
|
||||
// Paint a grid generated by the box
|
||||
|
@ -360,10 +360,20 @@ bool StandbyState::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
|
||||
case WHEEL_ZOOM: {
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
int zoom = MID(MIN_ZOOM, editor->zoom()-dz, MAX_ZOOM);
|
||||
if (editor->zoom() != zoom)
|
||||
Zoom zoom = editor->zoom();
|
||||
if (dz < 0) {
|
||||
while (dz++ < 0)
|
||||
zoom.in();
|
||||
}
|
||||
else {
|
||||
while (dz-- > 0)
|
||||
zoom.out();
|
||||
}
|
||||
|
||||
if (editor->zoom() != zoom) {
|
||||
editor->setZoomAndCenterInMouse(zoom,
|
||||
mouseMsg->position(), Editor::kDontCenterOnZoom);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -223,6 +223,7 @@ public:
|
||||
bool useMask() override { return m_useMask; }
|
||||
Mask* getMask() override { return m_mask; }
|
||||
gfx::Point getMaskOrigin() override { return m_maskOrigin; }
|
||||
const Zoom& zoom() override { return m_editor->zoom(); }
|
||||
ToolLoop::Button getMouseButton() override { return m_button; }
|
||||
int getPrimaryColor() override { return m_primary_color; }
|
||||
void setPrimaryColor(int color) override { m_primary_color = color; }
|
||||
|
@ -196,8 +196,8 @@ gfx::Rect TransformHandles::getPivotHandleBounds(Editor* editor,
|
||||
she::Surface* part = theme->get_part(PART_PIVOT_HANDLE);
|
||||
gfx::Point screenPivotPos = editor->editorToScreen(transform.pivot());
|
||||
|
||||
screenPivotPos.x += (1 << editor->zoom()) / 2;
|
||||
screenPivotPos.y += (1 << editor->zoom()) / 2;
|
||||
screenPivotPos.x += editor->zoom().apply(1) / 2;
|
||||
screenPivotPos.y += editor->zoom().apply(1) / 2;
|
||||
|
||||
return gfx::Rect(
|
||||
screenPivotPos.x-part->width()/2,
|
||||
|
@ -53,12 +53,12 @@ bool ZoomingState::onMouseDown(Editor* editor, MouseMessage* msg)
|
||||
|
||||
bool ZoomingState::onMouseUp(Editor* editor, MouseMessage* msg)
|
||||
{
|
||||
int zoom = editor->zoom();
|
||||
Zoom zoom = editor->zoom();
|
||||
|
||||
if (msg->left() && zoom < 5)
|
||||
++zoom;
|
||||
else if (msg->right() && zoom > 0)
|
||||
--zoom;
|
||||
if (msg->left())
|
||||
zoom.in();
|
||||
else if (msg->right())
|
||||
zoom.out();
|
||||
|
||||
editor->setZoomAndCenterInMouse(zoom,
|
||||
msg->position(), Editor::kCofiguredZoomBehavior);
|
||||
|
@ -245,7 +245,7 @@ void MiniEditorWindow::updateUsingEditor(Editor* editor)
|
||||
addChild(m_docView);
|
||||
|
||||
miniEditor = m_docView->getEditor();
|
||||
miniEditor->setZoom(0);
|
||||
miniEditor->setZoom(Zoom(1, 1));
|
||||
miniEditor->setState(EditorStatePtr(new EditorState));
|
||||
layout();
|
||||
}
|
||||
|
@ -115,9 +115,8 @@ public:
|
||||
};
|
||||
|
||||
template<class DstTraits, class SrcTraits>
|
||||
static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
||||
int x, int y, int opacity,
|
||||
int blend_mode, int zoom)
|
||||
static void merge_zoomed_image_scale_up(Image* dst, const Image* src, const Palette* pal,
|
||||
int x, int y, int opacity, int blend_mode, Zoom zoom)
|
||||
{
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode);
|
||||
int src_x, src_y, src_w, src_h;
|
||||
@ -126,8 +125,8 @@ static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
||||
int first_box_w, first_box_h;
|
||||
int line_h, bottom;
|
||||
|
||||
box_w = 1<<zoom;
|
||||
box_h = 1<<zoom;
|
||||
box_w = zoom.apply(1);
|
||||
box_h = zoom.apply(1);
|
||||
|
||||
src_x = 0;
|
||||
src_y = 0;
|
||||
@ -136,13 +135,13 @@ static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
||||
|
||||
dst_x = x;
|
||||
dst_y = y;
|
||||
dst_w = src->width()<<zoom;
|
||||
dst_h = src->height()<<zoom;
|
||||
dst_w = zoom.apply(src->width());
|
||||
dst_h = zoom.apply(src->height());
|
||||
|
||||
// clipping...
|
||||
if (dst_x < 0) {
|
||||
src_x += (-dst_x)>>zoom;
|
||||
src_w -= (-dst_x)>>zoom;
|
||||
src_x += zoom.remove(-dst_x);
|
||||
src_w -= zoom.remove(-dst_x);
|
||||
dst_w -= (-dst_x);
|
||||
first_box_w = box_w - ((-dst_x) % box_w);
|
||||
dst_x = 0;
|
||||
@ -151,8 +150,8 @@ static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
||||
first_box_w = 0;
|
||||
|
||||
if (dst_y < 0) {
|
||||
src_y += (-dst_y)>>zoom;
|
||||
src_h -= (-dst_y)>>zoom;
|
||||
src_y += zoom.remove(-dst_y);
|
||||
src_h -= zoom.remove(-dst_y);
|
||||
dst_h -= (-dst_y);
|
||||
first_box_h = box_h - ((-dst_y) % box_h);
|
||||
dst_y = 0;
|
||||
@ -161,12 +160,12 @@ static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
||||
first_box_h = 0;
|
||||
|
||||
if (dst_x+dst_w > dst->width()) {
|
||||
src_w -= (dst_x+dst_w-dst->width()) >> zoom;
|
||||
src_w -= zoom.remove(dst_x+dst_w-dst->width());
|
||||
dst_w = dst->width() - dst_x;
|
||||
}
|
||||
|
||||
if (dst_y+dst_h > dst->height()) {
|
||||
src_h -= (dst_y+dst_h-dst->height()) >> zoom;
|
||||
src_h -= zoom.remove(dst_y+dst_h-dst->height());
|
||||
dst_h = dst->height() - dst_y;
|
||||
}
|
||||
|
||||
@ -279,6 +278,107 @@ done_with_line:;
|
||||
done_with_blit:;
|
||||
}
|
||||
|
||||
template<class DstTraits, class SrcTraits>
|
||||
static void merge_zoomed_image_scale_down(Image* dst, const Image* src, const Palette* pal,
|
||||
int x, int y, int opacity, int blend_mode, Zoom zoom)
|
||||
{
|
||||
BlenderHelper<DstTraits, SrcTraits> blender(src, pal, blend_mode);
|
||||
int src_x, src_y, src_w, src_h;
|
||||
int dst_x, dst_y, dst_w, dst_h;
|
||||
int unbox_w, unbox_h;
|
||||
int bottom;
|
||||
|
||||
unbox_w = zoom.remove(1);
|
||||
unbox_h = zoom.remove(1);
|
||||
|
||||
src_x = 0;
|
||||
src_y = 0;
|
||||
src_w = src->width();
|
||||
src_h = src->height();
|
||||
|
||||
dst_x = x;
|
||||
dst_y = y;
|
||||
dst_w = zoom.apply(src->width());
|
||||
dst_h = zoom.apply(src->height());
|
||||
|
||||
// clipping...
|
||||
if (dst_x < 0) {
|
||||
src_x += zoom.remove(-dst_x);
|
||||
src_w -= zoom.remove(-dst_x);
|
||||
dst_w -= (-dst_x);
|
||||
dst_x = 0;
|
||||
}
|
||||
|
||||
if (dst_y < 0) {
|
||||
src_y += zoom.remove(-dst_y);
|
||||
src_h -= zoom.remove(-dst_y);
|
||||
dst_h -= (-dst_y);
|
||||
dst_y = 0;
|
||||
}
|
||||
|
||||
if (dst_x+dst_w > dst->width()) {
|
||||
src_w -= zoom.remove(dst_x+dst_w-dst->width());
|
||||
dst_w = dst->width() - dst_x;
|
||||
}
|
||||
|
||||
if (dst_y+dst_h > dst->height()) {
|
||||
src_h -= zoom.remove(dst_y+dst_h-dst->height());
|
||||
dst_h = dst->height() - dst_y;
|
||||
}
|
||||
|
||||
src_w = zoom.remove(zoom.apply(src_w));
|
||||
src_h = zoom.remove(zoom.apply(src_h));
|
||||
|
||||
if ((src_w <= 0) || (src_h <= 0) ||
|
||||
(dst_w <= 0) || (dst_h <= 0))
|
||||
return;
|
||||
|
||||
bottom = dst_y+dst_h-1;
|
||||
|
||||
// Lock all necessary bits
|
||||
const LockImageBits<SrcTraits> srcBits(src, gfx::Rect(src_x, src_y, src_w, src_h));
|
||||
LockImageBits<DstTraits> dstBits(dst, gfx::Rect(dst_x, dst_y, dst_w, dst_h));
|
||||
typename LockImageBits<SrcTraits>::const_iterator src_it = srcBits.begin();
|
||||
typename LockImageBits<SrcTraits>::const_iterator src_end = srcBits.end();
|
||||
typename LockImageBits<DstTraits>::iterator dst_it, dst_end;
|
||||
|
||||
// For each line to draw of the source image...
|
||||
for (y=0; y<src_h; y+=unbox_h) {
|
||||
dst_it = dstBits.begin_area(gfx::Rect(dst_x, dst_y, dst_w, 1));
|
||||
dst_end = dstBits.end_area(gfx::Rect(dst_x, dst_y, dst_w, 1));
|
||||
|
||||
for (x=0; x<src_w; x+=unbox_w) {
|
||||
ASSERT(src_it >= srcBits.begin() && src_it < src_end);
|
||||
ASSERT(dst_it >= dstBits.begin() && dst_it < dst_end);
|
||||
|
||||
blender(*dst_it, *dst_it, *src_it, opacity);
|
||||
|
||||
// Skip source pixels
|
||||
for (int delta=0; delta < unbox_w && src_it != src_end; ++delta)
|
||||
++src_it;
|
||||
|
||||
++dst_it;
|
||||
}
|
||||
|
||||
if (++dst_y > bottom)
|
||||
break;
|
||||
|
||||
// Skip lines
|
||||
for (int delta=0; delta < src_w * (unbox_h-1) && src_it != src_end; ++delta)
|
||||
++src_it;
|
||||
}
|
||||
}
|
||||
|
||||
template<class DstTraits, class SrcTraits>
|
||||
static void merge_zoomed_image(Image* dst, const Image* src, const Palette* pal,
|
||||
int x, int y, int opacity, int blend_mode, Zoom zoom)
|
||||
{
|
||||
if (zoom.scale() >= 1.0)
|
||||
merge_zoomed_image_scale_up<DstTraits, SrcTraits>(dst, src, pal, x, y, opacity, blend_mode, zoom);
|
||||
else
|
||||
merge_zoomed_image_scale_down<DstTraits, SrcTraits>(dst, src, pal, x, y, opacity, blend_mode, zoom);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Render Engine
|
||||
|
||||
@ -380,15 +480,15 @@ void RenderEngine::setPreviewImage(const Layer* layer, FrameNumber frame, Image*
|
||||
in a new image and return it.
|
||||
|
||||
Positions source_x, source_y, width and height must have the
|
||||
zoom applied (sorce_x<<zoom, source_y<<zoom, width<<zoom, etc.)
|
||||
zoom applied (zoom.apply(sorce_x), zoom.apply(source_y), zoom.apply(width), etc.)
|
||||
*/
|
||||
Image* RenderEngine::renderSprite(int source_x, int source_y,
|
||||
int width, int height,
|
||||
FrameNumber frame, int zoom,
|
||||
FrameNumber frame, Zoom zoom,
|
||||
bool draw_tiled_bg,
|
||||
bool enable_onionskin)
|
||||
{
|
||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, int);
|
||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom);
|
||||
const LayerImage* background = m_sprite->backgroundLayer();
|
||||
bool need_checked_bg = (background != NULL ? !background->isVisible(): true);
|
||||
uint32_t bg_color = 0;
|
||||
@ -471,7 +571,7 @@ Image* RenderEngine::renderSprite(int source_x, int source_y,
|
||||
// static
|
||||
void RenderEngine::renderCheckedBackground(Image* image,
|
||||
int source_x, int source_y,
|
||||
int zoom)
|
||||
Zoom zoom)
|
||||
{
|
||||
int x, y, u, v;
|
||||
int tile_w = 16;
|
||||
@ -504,13 +604,13 @@ void RenderEngine::renderCheckedBackground(Image* image,
|
||||
}
|
||||
|
||||
if (checked_bg_zoom) {
|
||||
tile_w <<= zoom;
|
||||
tile_h <<= zoom;
|
||||
tile_w = zoom.apply(tile_w);
|
||||
tile_h = zoom.apply(tile_h);
|
||||
}
|
||||
|
||||
// Tile size
|
||||
if (tile_w < (1<<zoom)) tile_w = (1<<zoom);
|
||||
if (tile_h < (1<<zoom)) tile_h = (1<<zoom);
|
||||
if (tile_w < zoom.apply(1)) tile_w = zoom.apply(1);
|
||||
if (tile_h < zoom.apply(1)) tile_h = zoom.apply(1);
|
||||
|
||||
// Tile position (u,v) is the number of tile we start in (source_x,source_y) coordinate
|
||||
u = (source_x / tile_w);
|
||||
@ -535,9 +635,9 @@ void RenderEngine::renderCheckedBackground(Image* image,
|
||||
|
||||
// static
|
||||
void RenderEngine::renderImage(Image* rgb_image, Image* src_image, const Palette* pal,
|
||||
int x, int y, int zoom)
|
||||
int x, int y, Zoom zoom)
|
||||
{
|
||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, int);
|
||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom);
|
||||
|
||||
ASSERT(rgb_image->pixelFormat() == IMAGE_RGB && "renderImage accepts RGB destination images only");
|
||||
|
||||
@ -566,8 +666,8 @@ void RenderEngine::renderLayer(
|
||||
const Layer* layer,
|
||||
Image *image,
|
||||
int source_x, int source_y,
|
||||
FrameNumber frame, int zoom,
|
||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, int),
|
||||
FrameNumber frame, Zoom zoom,
|
||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom),
|
||||
bool render_background,
|
||||
bool render_transparent,
|
||||
int blend_mode)
|
||||
@ -607,8 +707,8 @@ void RenderEngine::renderLayer(
|
||||
ASSERT(src_image->maskColor() == m_sprite->transparentColor());
|
||||
|
||||
(*zoomed_func)(image, src_image, m_sprite->getPalette(frame),
|
||||
(cel->x() << zoom) - source_x,
|
||||
(cel->y() << zoom) - source_y,
|
||||
zoom.apply(cel->x()) - source_x,
|
||||
zoom.apply(cel->y()) - source_y,
|
||||
output_opacity,
|
||||
(blend_mode < 0 ?
|
||||
static_cast<const LayerImage*>(layer)->getBlendMode():
|
||||
@ -645,8 +745,8 @@ void RenderEngine::renderLayer(
|
||||
Image* extraImage = m_document->getExtraCelImage();
|
||||
|
||||
(*zoomed_func)(image, extraImage, m_sprite->getPalette(frame),
|
||||
(extraCel->x() << zoom) - source_x,
|
||||
(extraCel->y() << zoom) - source_y,
|
||||
zoom.apply(extraCel->x()) - source_x,
|
||||
zoom.apply(extraCel->y()) - source_y,
|
||||
extraCel->opacity(),
|
||||
m_document->getExtraCelBlendMode(), zoom);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "app/color.h"
|
||||
#include "app/zoom.h"
|
||||
#include "doc/frame_number.h"
|
||||
|
||||
namespace doc {
|
||||
@ -70,7 +71,7 @@ namespace app {
|
||||
|
||||
Image* renderSprite(int source_x, int source_y,
|
||||
int width, int height,
|
||||
FrameNumber frame, int zoom,
|
||||
FrameNumber frame, Zoom zoom,
|
||||
bool draw_tiled_bg,
|
||||
bool enable_onionskin);
|
||||
|
||||
@ -79,18 +80,18 @@ namespace app {
|
||||
|
||||
static void renderCheckedBackground(Image* image,
|
||||
int source_x, int source_y,
|
||||
int zoom);
|
||||
Zoom zoom);
|
||||
|
||||
static void renderImage(Image* rgb_image, Image* src_image, const Palette* pal,
|
||||
int x, int y, int zoom);
|
||||
int x, int y, Zoom zoom);
|
||||
|
||||
private:
|
||||
void renderLayer(
|
||||
const Layer* layer,
|
||||
Image* image,
|
||||
int source_x, int source_y,
|
||||
FrameNumber frame, int zoom,
|
||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, int),
|
||||
FrameNumber frame, Zoom zoom,
|
||||
void (*zoomed_func)(Image*, const Image*, const Palette*, int, int, int, int, Zoom),
|
||||
bool render_background,
|
||||
bool render_transparent,
|
||||
int blend_mode);
|
||||
|
47
src/app/zoom.cpp
Normal file
47
src/app/zoom.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/* Aseprite
|
||||
* Copyright (C) 2001-2014 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/zoom.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
void Zoom::in()
|
||||
{
|
||||
if (m_den > 1) {
|
||||
m_den--;
|
||||
}
|
||||
else if (m_num < 64) {
|
||||
m_num++;
|
||||
}
|
||||
}
|
||||
|
||||
void Zoom::out()
|
||||
{
|
||||
if (m_num > 1) {
|
||||
m_num--;
|
||||
}
|
||||
else if (m_den < 32) {
|
||||
m_den++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
57
src/app/zoom.h
Normal file
57
src/app/zoom.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* Aseprite
|
||||
* Copyright (C) 2001-2014 David Capello
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef APP_ZOOM_H_INCLUDED
|
||||
#define APP_ZOOM_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
namespace app {
|
||||
|
||||
class Zoom {
|
||||
public:
|
||||
Zoom(int num, int den)
|
||||
: m_num(num), m_den(den) {
|
||||
}
|
||||
|
||||
double scale() const { return static_cast<double>(m_num) / static_cast<double>(m_den); }
|
||||
|
||||
int apply(int x) const { return x * m_num / m_den; }
|
||||
int remove(int x) const { return x * m_den / m_num; }
|
||||
|
||||
double apply(double x) const { return x * m_num / m_den; }
|
||||
double remove(double x) const { return x * m_den / m_num; }
|
||||
|
||||
void in();
|
||||
void out();
|
||||
|
||||
bool operator==(const Zoom& other) const {
|
||||
return m_num == other.m_num && m_den == other.m_den;
|
||||
}
|
||||
|
||||
bool operator!=(const Zoom& other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_num;
|
||||
int m_den;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif // APP_ZOOM_H_INCLUDED
|
Loading…
x
Reference in New Issue
Block a user