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 -->
<key command="ScrollCenter" shortcut="Shift+C" />
<key command="FitScreen" shortcut="Ctrl+0" mac="Cmd+0" />
<!-- Scroll with arrows -->
<key command="Scroll" shortcut="Space+Left">

View File

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

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
// 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<std::string>(int(100.0*m_zoom.scale())) + "%";
break;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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