diff --git a/data/gui.xml b/data/gui.xml
index f4fba37cf..54bcdd43c 100644
--- a/data/gui.xml
+++ b/data/gui.xml
@@ -224,6 +224,7 @@
+
diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt
index 32b7f38d5..8ddfa44cd 100644
--- a/src/app/CMakeLists.txt
+++ b/src/app/CMakeLists.txt
@@ -193,6 +193,7 @@ add_library(app-lib
commands/cmd_exit.cpp
commands/cmd_export_sprite_sheet.cpp
commands/cmd_eyedropper.cpp
+ commands/cmd_fit_screen.cpp
commands/cmd_flatten_layers.cpp
commands/cmd_flip.cpp
commands/cmd_frame_properties.cpp
diff --git a/src/app/commands/cmd_fit_screen.cpp b/src/app/commands/cmd_fit_screen.cpp
new file mode 100644
index 000000000..a8c6be011
--- /dev/null
+++ b/src/app/commands/cmd_fit_screen.cpp
@@ -0,0 +1,51 @@
+// Aseprite
+// Copyright (C) 2001-2016 David Capello
+//
+// 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/app.h"
+#include "app/commands/command.h"
+#include "app/context_access.h"
+#include "app/modules/editors.h"
+#include "app/ui/editor/editor.h"
+
+namespace app {
+
+class FitScreenCommand : public Command {
+public:
+ FitScreenCommand();
+ Command* clone() const override { return new FitScreenCommand(*this); }
+
+protected:
+ bool onEnabled(Context* context) override;
+ void onExecute(Context* context) override;
+};
+
+FitScreenCommand::FitScreenCommand()
+ : Command("FitScreen",
+ "Fit on Screen",
+ CmdUIOnlyFlag)
+{
+}
+
+bool FitScreenCommand::onEnabled(Context* context)
+{
+ return (current_editor != nullptr);
+}
+
+void FitScreenCommand::onExecute(Context* context)
+{
+ current_editor->setScrollAndZoomToFitScreen();
+}
+
+Command* CommandFactory::createFitScreenCommand()
+{
+ return new FitScreenCommand;
+}
+
+} //namespace app
diff --git a/src/app/commands/cmd_zoom.cpp b/src/app/commands/cmd_zoom.cpp
index 9e2090267..7043ba3b4 100644
--- a/src/app/commands/cmd_zoom.cpp
+++ b/src/app/commands/cmd_zoom.cpp
@@ -1,5 +1,5 @@
// Aseprite
-// Copyright (C) 2001-2015 David Capello
+// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
@@ -23,7 +23,8 @@ namespace app {
class ZoomCommand : public Command {
public:
- enum Action { In, Out, Set };
+ enum class Action { In, Out, Set };
+ enum class Focus { Default, Mouse, Center };
ZoomCommand();
Command* clone() const override { return new ZoomCommand(*this); }
@@ -37,29 +38,37 @@ protected:
private:
Action m_action;
render::Zoom m_zoom;
+ Focus m_focus;
};
ZoomCommand::ZoomCommand()
: Command("Zoom",
"Zoom",
CmdUIOnlyFlag)
+ , m_action(Action::In)
, m_zoom(1, 1)
+ , m_focus(Focus::Default)
{
}
void ZoomCommand::onLoadParams(const Params& params)
{
std::string action = params.get("action");
- if (action == "in") m_action = In;
- else if (action == "out") m_action = Out;
- else if (action == "set") m_action = Set;
+ if (action == "in") m_action = Action::In;
+ else if (action == "out") m_action = Action::Out;
+ else if (action == "set") m_action = Action::Set;
std::string percentage = params.get("percentage");
if (!percentage.empty()) {
m_zoom = render::Zoom::fromScale(
std::strtod(percentage.c_str(), NULL) / 100.0);
- m_action = Set;
+ m_action = Action::Set;
}
+
+ m_focus = Focus::Default;
+ std::string focus = params.get("focus");
+ if (focus == "center") m_focus = Focus::Center;
+ else if (focus == "mouse") m_focus = Focus::Mouse;
}
bool ZoomCommand::onEnabled(Context* context)
@@ -81,23 +90,31 @@ void ZoomCommand::onExecute(Context* context)
render::Zoom zoom = editor->zoom();
switch (m_action) {
- case In:
+ case Action::In:
zoom.in();
break;
- case Out:
+ case Action::Out:
zoom.out();
break;
- case Set:
+ case Action::Set:
zoom = m_zoom;
break;
}
- bool center = Preferences::instance().editor.zoomFromCenterWithKeys();
+ Focus focus = m_focus;
+ if (focus == Focus::Default) {
+ if (Preferences::instance().editor.zoomFromCenterWithKeys()) {
+ focus = Focus::Center;
+ }
+ else {
+ focus = Focus::Mouse;
+ }
+ }
editor->setZoomAndCenterInMouse(
zoom, mousePos,
- (center ? Editor::ZoomBehavior::CENTER:
- Editor::ZoomBehavior::MOUSE));
+ (focus == Focus::Center ? Editor::ZoomBehavior::CENTER:
+ Editor::ZoomBehavior::MOUSE));
}
std::string ZoomCommand::onGetFriendlyName() const
@@ -105,13 +122,13 @@ std::string ZoomCommand::onGetFriendlyName() const
std::string text = "Zoom";
switch (m_action) {
- case In:
+ case Action::In:
text += " in";
break;
- case Out:
+ case Action::Out:
text += " out";
break;
- case Set:
+ case Action::Set:
text += " " + base::convert_to(int(100.0*m_zoom.scale())) + "%";
break;
}
diff --git a/src/app/commands/commands_list.h b/src/app/commands/commands_list.h
index 0c8d6c4d1..b9be9ab69 100644
--- a/src/app/commands/commands_list.h
+++ b/src/app/commands/commands_list.h
@@ -37,6 +37,7 @@ FOR_EACH_COMMAND(DuplicateView)
FOR_EACH_COMMAND(Exit)
FOR_EACH_COMMAND(ExportSpriteSheet)
FOR_EACH_COMMAND(Eyedropper)
+FOR_EACH_COMMAND(FitScreen)
FOR_EACH_COMMAND(FlattenLayers)
FOR_EACH_COMMAND(Flip)
FOR_EACH_COMMAND(FrameProperties)
diff --git a/src/app/ui/context_bar.cpp b/src/app/ui/context_bar.cpp
index 480da2d84..2e076af6d 100644
--- a/src/app/ui/context_bar.cpp
+++ b/src/app/ui/context_bar.cpp
@@ -72,6 +72,52 @@ using namespace tools;
static bool g_updatingFromCode = false;
+class ContextBar::ZoomButtons : public ButtonSet {
+public:
+ ZoomButtons()
+ : ButtonSet(3) {
+ addItem("100%");
+ addItem("Center");
+ addItem("Fit Screen");
+ }
+
+private:
+ void onItemChange(Item* item) override {
+ ButtonSet::onItemChange(item);
+
+ Command* cmd = nullptr;
+ Params params;
+
+ switch (selectedItem()) {
+
+ case 0: {
+ cmd = CommandsModule::instance()->getCommandByName(CommandId::Zoom);
+ params.set("action", "set");
+ params.set("percentage", "100");
+ params.set("focus", "center");
+ UIContext::instance()->executeCommand(cmd, params);
+ break;
+ }
+
+ case 1: {
+ cmd = CommandsModule::instance()->getCommandByName(CommandId::ScrollCenter);
+ break;
+ }
+
+ case 2: {
+ cmd = CommandsModule::instance()->getCommandByName(CommandId::FitScreen);
+ break;
+ }
+ }
+
+ if (cmd)
+ UIContext::instance()->executeCommand(cmd, params);
+
+ deselectItems();
+ manager()->freeFocus();
+ }
+};
+
class ContextBar::BrushTypeField : public ButtonSet {
public:
BrushTypeField(ContextBar* owner)
@@ -1321,6 +1367,8 @@ ContextBar::ContextBar()
m_selectionOptionsBox->addChild(m_pivot = new PivotField);
m_selectionOptionsBox->addChild(m_rotAlgo = new RotAlgorithmField());
+ addChild(m_zoomButtons = new ZoomButtons);
+
addChild(m_brushType = new BrushTypeField(this));
addChild(m_brushSize = new BrushSizeField());
addChild(m_brushAngle = new BrushAngleField(m_brushType));
@@ -1581,6 +1629,13 @@ void ContextBar::updateForTool(tools::Tool* tool)
(activeBrush()->type() == kSquareBrushType ||
activeBrush()->type() == kLineBrushType);
+ // True if the current tool is eyedropper.
+ bool needZoomButtons = tool &&
+ (tool->getInk(0)->isZoom() ||
+ tool->getInk(1)->isZoom() ||
+ tool->getInk(0)->isScrollMovement() ||
+ tool->getInk(1)->isScrollMovement());
+
// True if the current tool is eyedropper.
bool isEyedropper = tool &&
(tool->getInk(0)->isEyedropper() ||
@@ -1620,6 +1675,7 @@ void ContextBar::updateForTool(tools::Tool* tool)
(isEffect));
// Show/Hide fields
+ m_zoomButtons->setVisible(needZoomButtons);
m_brushType->setVisible(supportOpacity && (!isFloodfill || (isFloodfill && hasImageBrush)));
m_brushSize->setVisible(supportOpacity && !isFloodfill && !hasImageBrush);
m_brushAngle->setVisible(supportOpacity && !isFloodfill && !hasImageBrush && hasBrushWithAngle);
diff --git a/src/app/ui/context_bar.h b/src/app/ui/context_bar.h
index 715541b25..9d9d7aad8 100644
--- a/src/app/ui/context_bar.h
+++ b/src/app/ui/context_bar.h
@@ -87,6 +87,7 @@ namespace app {
// ActiveToolObserver impl
void onActiveToolChange(tools::Tool* tool) override;
+ class ZoomButtons;
class BrushTypeField;
class BrushAngleField;
class BrushSizeField;
@@ -109,6 +110,7 @@ namespace app {
class AutoSelectLayerField;
class SymmetryField;
+ ZoomButtons* m_zoomButtons;
BrushTypeField* m_brushType;
BrushAngleField* m_brushAngle;
BrushSizeField* m_brushSize;
diff --git a/src/app/ui/editor/editor.cpp b/src/app/ui/editor/editor.cpp
index de563ec87..2216b9ce6 100644
--- a/src/app/ui/editor/editor.cpp
+++ b/src/app/ui/editor/editor.cpp
@@ -387,6 +387,60 @@ void Editor::setDefaultScroll()
m_padding.y - vp.h/2 + m_zoom.apply(m_sprite->height())/2));
}
+void Editor::setScrollAndZoomToFitScreen()
+{
+ View* view = View::getView(this);
+ Rect vp = view->viewportBounds();
+ Zoom zoom = m_zoom;
+
+ if (float(vp.w) / float(m_sprite->width()) <
+ float(vp.h) / float(m_sprite->height())) {
+ if (vp.w < zoom.apply(m_sprite->width())) {
+ while (vp.w < zoom.apply(m_sprite->width()))
+ if (!zoom.out())
+ break;
+ }
+ else if (vp.w > zoom.apply(m_sprite->width())) {
+ bool out = true;
+ while (vp.w > zoom.apply(m_sprite->width())) {
+ if (!zoom.in()) {
+ out = false;
+ break;
+ }
+ }
+ if (out)
+ zoom.out();
+ }
+ }
+ else {
+ if (vp.h < zoom.apply(m_sprite->height())) {
+ while (vp.h < zoom.apply(m_sprite->height())) {
+ if (!zoom.out())
+ break;
+ }
+ }
+ else if (vp.h > zoom.apply(m_sprite->height())) {
+ bool out = true;
+ while (vp.h > zoom.apply(m_sprite->height())) {
+ if (!zoom.in()) {
+ out = false;
+ break;
+ }
+ }
+ if (out)
+ zoom.out();
+ }
+ }
+
+ setZoom(zoom);
+
+ updateEditor();
+ setEditorScroll(
+ gfx::Point(
+ m_padding.x - vp.w/2 + zoom.apply(m_sprite->width())/2,
+ m_padding.y - vp.h/2 + zoom.apply(m_sprite->height())/2));
+}
+
// Sets the scroll position of the editor
void Editor::setEditorScroll(const gfx::Point& scroll)
{
diff --git a/src/app/ui/editor/editor.h b/src/app/ui/editor/editor.h
index e79891a9e..f467cf686 100644
--- a/src/app/ui/editor/editor.h
+++ b/src/app/ui/editor/editor.h
@@ -135,6 +135,7 @@ namespace app {
void setZoom(const render::Zoom& zoom);
void setDefaultScroll();
+ void setScrollAndZoomToFitScreen();
void setEditorScroll(const gfx::Point& scroll);
void setEditorZoom(const render::Zoom& zoom);
diff --git a/src/render/zoom.cpp b/src/render/zoom.cpp
index eb7169bba..a442d2e3a 100644
--- a/src/render/zoom.cpp
+++ b/src/render/zoom.cpp
@@ -53,7 +53,7 @@ Zoom::Zoom(int num, int den)
m_internalScale = scale();
}
-void Zoom::in()
+bool Zoom::in()
{
int i = linearScale();
if (i < scales_size-1) {
@@ -61,10 +61,13 @@ void Zoom::in()
m_num = scales[i][0];
m_den = scales[i][1];
m_internalScale = scale();
+ return true;
}
+ else
+ return false;
}
-void Zoom::out()
+bool Zoom::out()
{
int i = linearScale();
if (i > 0) {
@@ -72,7 +75,10 @@ void Zoom::out()
m_num = scales[i][0];
m_den = scales[i][1];
m_internalScale = scale();
+ return true;
}
+ else
+ return false;
}
int Zoom::linearScale() const
diff --git a/src/render/zoom.h b/src/render/zoom.h
index a56b9f910..2df7d3182 100644
--- a/src/render/zoom.h
+++ b/src/render/zoom.h
@@ -1,5 +1,5 @@
// Aseprite Render Library
-// Copyright (c) 2001-2015 David Capello
+// Copyright (c) 2001-2016 David Capello
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@@ -51,8 +51,8 @@ namespace render {
remove(r.y+r.h) - remove(r.y));
}
- void in();
- void out();
+ bool in();
+ bool out();
// Returns an linear zoom scale. This position can be incremented
// or decremented to get a new zoom value.