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.