Add zoom/scroll buttons in ContextBar (including a new "Fit Screen" command)

This commit is contained in:
David Capello 2016-09-15 09:50:00 -03:00
parent ada6c0666c
commit 1c7abd285e
11 changed files with 210 additions and 20 deletions

View File

@ -224,6 +224,7 @@
<!-- Scroll to center --> <!-- Scroll to center -->
<key command="ScrollCenter" shortcut="Shift+C" /> <key command="ScrollCenter" shortcut="Shift+C" />
<key command="FitScreen" shortcut="Ctrl+0" mac="Cmd+0" />
<!-- Scroll with arrows --> <!-- Scroll with arrows -->
<key command="Scroll" shortcut="Space+Left"> <key command="Scroll" shortcut="Space+Left">

View File

@ -193,6 +193,7 @@ add_library(app-lib
commands/cmd_exit.cpp commands/cmd_exit.cpp
commands/cmd_export_sprite_sheet.cpp commands/cmd_export_sprite_sheet.cpp
commands/cmd_eyedropper.cpp commands/cmd_eyedropper.cpp
commands/cmd_fit_screen.cpp
commands/cmd_flatten_layers.cpp commands/cmd_flatten_layers.cpp
commands/cmd_flip.cpp commands/cmd_flip.cpp
commands/cmd_frame_properties.cpp commands/cmd_frame_properties.cpp

View File

@ -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

View File

@ -1,5 +1,5 @@
// Aseprite // Aseprite
// Copyright (C) 2001-2015 David Capello // Copyright (C) 2001-2016 David Capello
// //
// This program is distributed under the terms of // This program is distributed under the terms of
// the End-User License Agreement for Aseprite. // the End-User License Agreement for Aseprite.
@ -23,7 +23,8 @@ namespace app {
class ZoomCommand : public Command { class ZoomCommand : public Command {
public: public:
enum Action { In, Out, Set }; enum class Action { In, Out, Set };
enum class Focus { Default, Mouse, Center };
ZoomCommand(); ZoomCommand();
Command* clone() const override { return new ZoomCommand(*this); } Command* clone() const override { return new ZoomCommand(*this); }
@ -37,29 +38,37 @@ protected:
private: private:
Action m_action; Action m_action;
render::Zoom m_zoom; render::Zoom m_zoom;
Focus m_focus;
}; };
ZoomCommand::ZoomCommand() ZoomCommand::ZoomCommand()
: Command("Zoom", : Command("Zoom",
"Zoom", "Zoom",
CmdUIOnlyFlag) CmdUIOnlyFlag)
, m_action(Action::In)
, m_zoom(1, 1) , m_zoom(1, 1)
, m_focus(Focus::Default)
{ {
} }
void ZoomCommand::onLoadParams(const Params& params) void ZoomCommand::onLoadParams(const Params& params)
{ {
std::string action = params.get("action"); std::string action = params.get("action");
if (action == "in") m_action = In; if (action == "in") m_action = Action::In;
else if (action == "out") m_action = Out; else if (action == "out") m_action = Action::Out;
else if (action == "set") m_action = Set; else if (action == "set") m_action = Action::Set;
std::string percentage = params.get("percentage"); std::string percentage = params.get("percentage");
if (!percentage.empty()) { if (!percentage.empty()) {
m_zoom = render::Zoom::fromScale( m_zoom = render::Zoom::fromScale(
std::strtod(percentage.c_str(), NULL) / 100.0); 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) bool ZoomCommand::onEnabled(Context* context)
@ -81,23 +90,31 @@ void ZoomCommand::onExecute(Context* context)
render::Zoom zoom = editor->zoom(); render::Zoom zoom = editor->zoom();
switch (m_action) { switch (m_action) {
case In: case Action::In:
zoom.in(); zoom.in();
break; break;
case Out: case Action::Out:
zoom.out(); zoom.out();
break; break;
case Set: case Action::Set:
zoom = m_zoom; zoom = m_zoom;
break; 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( editor->setZoomAndCenterInMouse(
zoom, mousePos, zoom, mousePos,
(center ? Editor::ZoomBehavior::CENTER: (focus == Focus::Center ? Editor::ZoomBehavior::CENTER:
Editor::ZoomBehavior::MOUSE)); Editor::ZoomBehavior::MOUSE));
} }
std::string ZoomCommand::onGetFriendlyName() const std::string ZoomCommand::onGetFriendlyName() const
@ -105,13 +122,13 @@ std::string ZoomCommand::onGetFriendlyName() const
std::string text = "Zoom"; std::string text = "Zoom";
switch (m_action) { switch (m_action) {
case In: case Action::In:
text += " in"; text += " in";
break; break;
case Out: case Action::Out:
text += " out"; text += " out";
break; break;
case Set: case Action::Set:
text += " " + base::convert_to<std::string>(int(100.0*m_zoom.scale())) + "%"; text += " " + base::convert_to<std::string>(int(100.0*m_zoom.scale())) + "%";
break; break;
} }

View File

@ -37,6 +37,7 @@ FOR_EACH_COMMAND(DuplicateView)
FOR_EACH_COMMAND(Exit) FOR_EACH_COMMAND(Exit)
FOR_EACH_COMMAND(ExportSpriteSheet) FOR_EACH_COMMAND(ExportSpriteSheet)
FOR_EACH_COMMAND(Eyedropper) FOR_EACH_COMMAND(Eyedropper)
FOR_EACH_COMMAND(FitScreen)
FOR_EACH_COMMAND(FlattenLayers) FOR_EACH_COMMAND(FlattenLayers)
FOR_EACH_COMMAND(Flip) FOR_EACH_COMMAND(Flip)
FOR_EACH_COMMAND(FrameProperties) FOR_EACH_COMMAND(FrameProperties)

View File

@ -72,6 +72,52 @@ using namespace tools;
static bool g_updatingFromCode = false; 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 { class ContextBar::BrushTypeField : public ButtonSet {
public: public:
BrushTypeField(ContextBar* owner) BrushTypeField(ContextBar* owner)
@ -1321,6 +1367,8 @@ ContextBar::ContextBar()
m_selectionOptionsBox->addChild(m_pivot = new PivotField); m_selectionOptionsBox->addChild(m_pivot = new PivotField);
m_selectionOptionsBox->addChild(m_rotAlgo = new RotAlgorithmField()); m_selectionOptionsBox->addChild(m_rotAlgo = new RotAlgorithmField());
addChild(m_zoomButtons = new ZoomButtons);
addChild(m_brushType = new BrushTypeField(this)); addChild(m_brushType = new BrushTypeField(this));
addChild(m_brushSize = new BrushSizeField()); addChild(m_brushSize = new BrushSizeField());
addChild(m_brushAngle = new BrushAngleField(m_brushType)); addChild(m_brushAngle = new BrushAngleField(m_brushType));
@ -1581,6 +1629,13 @@ void ContextBar::updateForTool(tools::Tool* tool)
(activeBrush()->type() == kSquareBrushType || (activeBrush()->type() == kSquareBrushType ||
activeBrush()->type() == kLineBrushType); 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. // True if the current tool is eyedropper.
bool isEyedropper = tool && bool isEyedropper = tool &&
(tool->getInk(0)->isEyedropper() || (tool->getInk(0)->isEyedropper() ||
@ -1620,6 +1675,7 @@ void ContextBar::updateForTool(tools::Tool* tool)
(isEffect)); (isEffect));
// Show/Hide fields // Show/Hide fields
m_zoomButtons->setVisible(needZoomButtons);
m_brushType->setVisible(supportOpacity && (!isFloodfill || (isFloodfill && hasImageBrush))); m_brushType->setVisible(supportOpacity && (!isFloodfill || (isFloodfill && hasImageBrush)));
m_brushSize->setVisible(supportOpacity && !isFloodfill && !hasImageBrush); m_brushSize->setVisible(supportOpacity && !isFloodfill && !hasImageBrush);
m_brushAngle->setVisible(supportOpacity && !isFloodfill && !hasImageBrush && hasBrushWithAngle); m_brushAngle->setVisible(supportOpacity && !isFloodfill && !hasImageBrush && hasBrushWithAngle);

View File

@ -87,6 +87,7 @@ namespace app {
// ActiveToolObserver impl // ActiveToolObserver impl
void onActiveToolChange(tools::Tool* tool) override; void onActiveToolChange(tools::Tool* tool) override;
class ZoomButtons;
class BrushTypeField; class BrushTypeField;
class BrushAngleField; class BrushAngleField;
class BrushSizeField; class BrushSizeField;
@ -109,6 +110,7 @@ namespace app {
class AutoSelectLayerField; class AutoSelectLayerField;
class SymmetryField; class SymmetryField;
ZoomButtons* m_zoomButtons;
BrushTypeField* m_brushType; BrushTypeField* m_brushType;
BrushAngleField* m_brushAngle; BrushAngleField* m_brushAngle;
BrushSizeField* m_brushSize; BrushSizeField* m_brushSize;

View File

@ -387,6 +387,60 @@ void Editor::setDefaultScroll()
m_padding.y - vp.h/2 + m_zoom.apply(m_sprite->height())/2)); 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 // Sets the scroll position of the editor
void Editor::setEditorScroll(const gfx::Point& scroll) void Editor::setEditorScroll(const gfx::Point& scroll)
{ {

View File

@ -135,6 +135,7 @@ namespace app {
void setZoom(const render::Zoom& zoom); void setZoom(const render::Zoom& zoom);
void setDefaultScroll(); void setDefaultScroll();
void setScrollAndZoomToFitScreen();
void setEditorScroll(const gfx::Point& scroll); void setEditorScroll(const gfx::Point& scroll);
void setEditorZoom(const render::Zoom& zoom); void setEditorZoom(const render::Zoom& zoom);

View File

@ -53,7 +53,7 @@ Zoom::Zoom(int num, int den)
m_internalScale = scale(); m_internalScale = scale();
} }
void Zoom::in() bool Zoom::in()
{ {
int i = linearScale(); int i = linearScale();
if (i < scales_size-1) { if (i < scales_size-1) {
@ -61,10 +61,13 @@ void Zoom::in()
m_num = scales[i][0]; m_num = scales[i][0];
m_den = scales[i][1]; m_den = scales[i][1];
m_internalScale = scale(); m_internalScale = scale();
return true;
} }
else
return false;
} }
void Zoom::out() bool Zoom::out()
{ {
int i = linearScale(); int i = linearScale();
if (i > 0) { if (i > 0) {
@ -72,7 +75,10 @@ void Zoom::out()
m_num = scales[i][0]; m_num = scales[i][0];
m_den = scales[i][1]; m_den = scales[i][1];
m_internalScale = scale(); m_internalScale = scale();
return true;
} }
else
return false;
} }
int Zoom::linearScale() const int Zoom::linearScale() const

View File

@ -1,5 +1,5 @@
// Aseprite Render Library // 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. // This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information. // Read LICENSE.txt for more information.
@ -51,8 +51,8 @@ namespace render {
remove(r.y+r.h) - remove(r.y)); remove(r.y+r.h) - remove(r.y));
} }
void in(); bool in();
void out(); bool out();
// Returns an linear zoom scale. This position can be incremented // Returns an linear zoom scale. This position can be incremented
// or decremented to get a new zoom value. // or decremented to get a new zoom value.