mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-02 13:20:12 +00:00
Now we have one editor for each Document we want to edit. Before we were creating one editor and switching the document on it, but now we have several Editors (one for each opened Document). This simplifies the Document implementation, because it doesn't need to know temporal Editor information (like "preferred editor settings"). - Removed all code from modules/editors.cpp (legacy from C code). - Removed PreferredEditorSettings class and Document::getPreferredEditorSettings(). - Added Workspace/WorkspaceView classes. - Added DocumentView (a DocumentObserver). - Added MiniEditorWindow class. - Removed SelectFileCommand & CloseEditorCommand. - Added TabView interface instead of using a raw void* in Tabs/TabsDelegate classes. - Modified editors_draw_sprite() calls to Document::notifySpritePixelsModified notifications. - The "current_editor" global variable wasn't removed because it's used in several places yet, but it will be removed in the near future. (Also this variable now can be NULL when we don't have an opened document.)
543 lines
16 KiB
C++
543 lines
16 KiB
C++
/* ASEPRITE
|
|
* Copyright (C) 2001-2012 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
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "app.h"
|
|
#include "app/find_widget.h"
|
|
#include "app/load_widget.h"
|
|
#include "base/bind.h"
|
|
#include "commands/command.h"
|
|
#include "commands/commands.h"
|
|
#include "console.h"
|
|
#include "document_wrappers.h"
|
|
#include "gfx/size.h"
|
|
#include "modules/editors.h"
|
|
#include "modules/gfx.h"
|
|
#include "modules/gui.h"
|
|
#include "raster/image.h"
|
|
#include "raster/mask.h"
|
|
#include "raster/pen.h"
|
|
#include "raster/sprite.h"
|
|
#include "settings/document_settings.h"
|
|
#include "settings/settings.h"
|
|
#include "skin/skin_parts.h"
|
|
#include "tools/ink.h"
|
|
#include "tools/point_shape.h"
|
|
#include "tools/tool.h"
|
|
#include "ui/gui.h"
|
|
#include "ui_context.h"
|
|
#include "widgets/button_set.h"
|
|
#include "widgets/color_button.h"
|
|
#include "widgets/editor/editor.h"
|
|
#include "widgets/status_bar.h"
|
|
|
|
#include <allegro.h>
|
|
|
|
using namespace gfx;
|
|
using namespace ui;
|
|
using namespace tools;
|
|
|
|
static Window* window = NULL;
|
|
|
|
static bool window_close_hook(Widget* widget, void *data);
|
|
|
|
class BrushPreview : public Widget
|
|
{
|
|
public:
|
|
BrushPreview() : Widget(JI_WIDGET) {
|
|
}
|
|
|
|
protected:
|
|
bool onProcessMessage(Message* msg)
|
|
{
|
|
switch (msg->type) {
|
|
|
|
case JM_DRAW: {
|
|
BITMAP *bmp = create_bitmap(jrect_w(this->rc),
|
|
jrect_h(this->rc));
|
|
|
|
Tool* current_tool = UIContext::instance()
|
|
->getSettings()
|
|
->getCurrentTool();
|
|
|
|
IPenSettings* pen_settings = UIContext::instance()
|
|
->getSettings()
|
|
->getToolSettings(current_tool)
|
|
->getPen();
|
|
|
|
ASSERT(pen_settings != NULL);
|
|
|
|
UniquePtr<Pen> pen(new Pen(pen_settings->getType(),
|
|
pen_settings->getSize(),
|
|
pen_settings->getAngle()));
|
|
|
|
clear_to_color(bmp, makecol(0, 0, 0));
|
|
image_to_allegro(pen->get_image(), bmp,
|
|
bmp->w/2 - pen->get_size()/2,
|
|
bmp->h/2 - pen->get_size()/2, NULL);
|
|
blit(bmp, ji_screen, 0, 0, this->rc->x1, this->rc->y1,
|
|
bmp->w, bmp->h);
|
|
destroy_bitmap(bmp);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return Widget::onProcessMessage(msg);
|
|
}
|
|
};
|
|
|
|
// Slot for App::Exit signal
|
|
static void on_exit_delete_this_widget()
|
|
{
|
|
ASSERT(window != NULL);
|
|
delete window;
|
|
}
|
|
|
|
static void on_pen_size_after_change()
|
|
{
|
|
Slider* brush_size = window->findChildT<Slider>("brush_size");
|
|
BrushPreview* brushPreview = window->findChildT<BrushPreview>("brush_preview");
|
|
|
|
ASSERT(brush_size != NULL);
|
|
|
|
Tool* current_tool = UIContext::instance()
|
|
->getSettings()
|
|
->getCurrentTool();
|
|
|
|
IToolSettings* tool_settings = UIContext::instance()
|
|
->getSettings()
|
|
->getToolSettings(current_tool);
|
|
|
|
brush_size->setValue(tool_settings->getPen()->getSize());
|
|
|
|
// Regenerate the preview
|
|
brushPreview->invalidate();
|
|
}
|
|
|
|
static void on_current_tool_change()
|
|
{
|
|
Slider* brush_size = window->findChildT<Slider>("brush_size");
|
|
Slider* brush_angle = window->findChildT<Slider>("brush_angle");
|
|
ButtonSet* brush_type = window->findChildT<ButtonSet>("brush_type");
|
|
BrushPreview* brushPreview = window->findChildT<BrushPreview>("brush_preview");
|
|
Widget* opacity_label = window->findChild("opacity_label");
|
|
Slider* opacity = window->findChildT<Slider>("opacity");
|
|
Widget* tolerance_label = window->findChild("tolerance_label");
|
|
Slider* tolerance = window->findChildT<Slider>("tolerance");
|
|
Widget* spray_box = window->findChild("spray_box");
|
|
Slider* spray_width = window->findChildT<Slider>("spray_width");
|
|
Slider* air_speed = window->findChildT<Slider>("air_speed");
|
|
|
|
Tool* current_tool = UIContext::instance()
|
|
->getSettings()
|
|
->getCurrentTool();
|
|
|
|
IToolSettings* tool_settings = UIContext::instance()
|
|
->getSettings()
|
|
->getToolSettings(current_tool);
|
|
|
|
opacity->setValue(tool_settings->getOpacity());
|
|
tolerance->setValue(tool_settings->getTolerance());
|
|
brush_size->setValue(tool_settings->getPen()->getSize());
|
|
brush_angle->setValue(tool_settings->getPen()->getAngle());
|
|
spray_width->setValue(tool_settings->getSprayWidth());
|
|
air_speed->setValue(tool_settings->getSpraySpeed());
|
|
|
|
// Select the brush type
|
|
brush_type->setSelectedItem(tool_settings->getPen()->getType());
|
|
|
|
// Regenerate the preview
|
|
brushPreview->invalidate();
|
|
|
|
// True if the current tool needs opacity options
|
|
bool hasOpacity = (current_tool->getInk(0)->isPaint() ||
|
|
current_tool->getInk(0)->isEffect() ||
|
|
current_tool->getInk(1)->isPaint() ||
|
|
current_tool->getInk(1)->isEffect());
|
|
|
|
// True if the current tool needs tolerance options
|
|
bool hasTolerance = (current_tool->getPointShape(0)->isFloodFill() ||
|
|
current_tool->getPointShape(1)->isFloodFill());
|
|
|
|
// True if the current tool needs spray options
|
|
bool hasSprayOptions = (current_tool->getPointShape(0)->isSpray() ||
|
|
current_tool->getPointShape(1)->isSpray());
|
|
|
|
// Show/Hide parameters
|
|
opacity_label->setVisible(hasOpacity);
|
|
opacity->setVisible(hasOpacity);
|
|
tolerance_label->setVisible(hasTolerance);
|
|
tolerance->setVisible(hasTolerance);
|
|
spray_box->setVisible(hasSprayOptions);
|
|
|
|
// Get the required size of the whole window
|
|
Size reqSize = window->getPreferredSize();
|
|
if (jrect_w(window->rc) < reqSize.w ||
|
|
jrect_h(window->rc) != reqSize.h) {
|
|
JRect rect = jrect_new(window->rc->x1, window->rc->y1,
|
|
(jrect_w(window->rc) < reqSize.w) ? window->rc->x1 + reqSize.w:
|
|
window->rc->x2,
|
|
window->rc->y1 + reqSize.h);
|
|
|
|
// Show the expanded area inside the screen
|
|
if (rect->y2 > JI_SCREEN_H)
|
|
jrect_displace(rect, 0, JI_SCREEN_H - rect->y2);
|
|
|
|
window->moveWindow(rect);
|
|
jrect_free(rect);
|
|
}
|
|
else
|
|
window->setBounds(window->getBounds()); // TODO layout() method is missing
|
|
|
|
// Redraw the window
|
|
window->invalidate();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
class ConfigureTools : public Command
|
|
{
|
|
public:
|
|
ConfigureTools();
|
|
Command* clone() const { return new ConfigureTools(*this); }
|
|
|
|
protected:
|
|
void onExecute(Context* context);
|
|
|
|
private:
|
|
CheckBox* m_tiled;
|
|
CheckBox* m_tiledX;
|
|
CheckBox* m_tiledY;
|
|
CheckBox* m_pixelGrid;
|
|
CheckBox* m_snapToGrid;
|
|
CheckBox* m_onionSkin;
|
|
CheckBox* m_viewGrid;
|
|
Widget* m_brushPreview;
|
|
ButtonSet* m_brushType;
|
|
Slider* m_brushSize;
|
|
Slider* m_brushAngle;
|
|
Slider* m_opacity;
|
|
Slider* m_tolerance;
|
|
Slider* m_sprayWidth;
|
|
Slider* m_airSpeed;
|
|
ISettings* m_settings;
|
|
IDocumentSettings* m_docSettings;
|
|
|
|
void onWindowClose();
|
|
void onTiledClick();
|
|
void onTiledXYClick(int tiled_axis, CheckBox* checkbox);
|
|
void onViewGridClick();
|
|
void onPixelGridClick();
|
|
void onSetGridClick();
|
|
void onSnapToGridClick();
|
|
void onOnionSkinClick();
|
|
void onBrushSizeSliderChange();
|
|
void onBrushAngleSliderChange();
|
|
void onOpacitySliderChange();
|
|
void onToleranceSliderChange();
|
|
void onSprayWidthSliderChange();
|
|
void onAirSpeedSliderChange();
|
|
void onBrushTypeChange();
|
|
|
|
};
|
|
|
|
ConfigureTools::ConfigureTools()
|
|
: Command("ConfigureTools",
|
|
"Configure Tools",
|
|
CmdUIOnlyFlag)
|
|
{
|
|
m_settings = NULL;
|
|
m_docSettings = NULL;
|
|
}
|
|
|
|
void ConfigureTools::onExecute(Context* context)
|
|
{
|
|
m_settings = UIContext::instance()->getSettings();
|
|
m_docSettings = m_settings->getDocumentSettings(NULL);
|
|
|
|
Button* set_grid;
|
|
Widget* brush_preview_box;
|
|
Widget* brush_type_box;
|
|
bool first_time = false;
|
|
|
|
if (!window) {
|
|
window = app::load_widget<Window>("tools_configuration.xml", "configure_tool");
|
|
first_time = true;
|
|
}
|
|
// If the window is opened, close it
|
|
else if (window->isVisible()) {
|
|
window->closeWindow(NULL);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
m_tiled = app::find_widget<CheckBox>(window, "tiled");
|
|
m_tiledX = app::find_widget<CheckBox>(window, "tiled_x");
|
|
m_tiledY = app::find_widget<CheckBox>(window, "tiled_y");
|
|
m_snapToGrid = app::find_widget<CheckBox>(window, "snap_to_grid");
|
|
m_viewGrid = app::find_widget<CheckBox>(window, "view_grid");
|
|
m_pixelGrid = app::find_widget<CheckBox>(window, "pixel_grid");
|
|
set_grid = app::find_widget<Button>(window, "set_grid");
|
|
m_brushSize = app::find_widget<Slider>(window, "brush_size");
|
|
m_brushAngle = app::find_widget<Slider>(window, "brush_angle");
|
|
m_opacity = app::find_widget<Slider>(window, "opacity");
|
|
m_tolerance = app::find_widget<Slider>(window, "tolerance");
|
|
m_sprayWidth = app::find_widget<Slider>(window, "spray_width");
|
|
m_airSpeed = app::find_widget<Slider>(window, "air_speed");
|
|
brush_preview_box = app::find_widget<Widget>(window, "brush_preview_box");
|
|
brush_type_box = app::find_widget<Widget>(window, "brush_type_box");
|
|
m_onionSkin = app::find_widget<CheckBox>(window, "onionskin");
|
|
}
|
|
catch (...) {
|
|
delete window;
|
|
window = NULL;
|
|
throw;
|
|
}
|
|
|
|
/* brush-preview */
|
|
if (first_time) {
|
|
m_brushPreview = new BrushPreview();
|
|
m_brushPreview->min_w = 32 + 4;
|
|
m_brushPreview->min_h = 32 + 4;
|
|
m_brushPreview->setId("brush_preview");
|
|
}
|
|
else {
|
|
m_brushPreview = window->findChild("brush_preview");
|
|
}
|
|
|
|
// Current settings
|
|
Tool* current_tool = m_settings->getCurrentTool();
|
|
IToolSettings* tool_settings = m_settings->getToolSettings(current_tool);
|
|
|
|
/* brush-type */
|
|
if (first_time) {
|
|
PenType type = tool_settings->getPen()->getType();
|
|
|
|
m_brushType = new ButtonSet(3, 1, type,
|
|
PART_BRUSH_CIRCLE,
|
|
PART_BRUSH_SQUARE,
|
|
PART_BRUSH_LINE);
|
|
|
|
m_brushType->setId("brush_type");
|
|
}
|
|
else {
|
|
m_brushType = window->findChildT<ButtonSet>("brush_type");
|
|
}
|
|
|
|
if (m_docSettings->getTiledMode() != TILED_NONE) {
|
|
m_tiled->setSelected(true);
|
|
if (m_docSettings->getTiledMode() & TILED_X_AXIS) m_tiledX->setSelected(true);
|
|
if (m_docSettings->getTiledMode() & TILED_Y_AXIS) m_tiledY->setSelected(true);
|
|
}
|
|
|
|
if (m_docSettings->getSnapToGrid()) m_snapToGrid->setSelected(true);
|
|
if (m_docSettings->getGridVisible()) m_viewGrid->setSelected(true);
|
|
if (m_docSettings->getPixelGridVisible()) m_pixelGrid->setSelected(true);
|
|
if (m_docSettings->getUseOnionskin()) m_onionSkin->setSelected(true);
|
|
|
|
if (first_time) {
|
|
// Append children
|
|
brush_preview_box->addChild(m_brushPreview);
|
|
brush_type_box->addChild(m_brushType);
|
|
|
|
// Slots
|
|
window->Close.connect(Bind<void>(&ConfigureTools::onWindowClose, this));
|
|
m_tiled->Click.connect(Bind<void>(&ConfigureTools::onTiledClick, this));
|
|
m_tiledX->Click.connect(Bind<void>(&ConfigureTools::onTiledXYClick, this, TILED_X_AXIS, m_tiledX));
|
|
m_tiledY->Click.connect(Bind<void>(&ConfigureTools::onTiledXYClick, this, TILED_Y_AXIS, m_tiledY));
|
|
m_viewGrid->Click.connect(Bind<void>(&ConfigureTools::onViewGridClick, this));
|
|
m_pixelGrid->Click.connect(Bind<void>(&ConfigureTools::onPixelGridClick, this));
|
|
set_grid->Click.connect(Bind<void>(&ConfigureTools::onSetGridClick, this));
|
|
m_snapToGrid->Click.connect(Bind<void>(&ConfigureTools::onSnapToGridClick, this));
|
|
m_onionSkin->Click.connect(Bind<void>(&ConfigureTools::onOnionSkinClick, this));
|
|
|
|
App::instance()->Exit.connect(&on_exit_delete_this_widget);
|
|
App::instance()->PenSizeAfterChange.connect(&on_pen_size_after_change);
|
|
App::instance()->CurrentToolChange.connect(&on_current_tool_change);
|
|
|
|
// Append hooks
|
|
m_brushSize->Change.connect(Bind<void>(&ConfigureTools::onBrushSizeSliderChange, this));
|
|
m_brushAngle->Change.connect(Bind<void>(&ConfigureTools::onBrushAngleSliderChange, this));
|
|
m_opacity->Change.connect(&ConfigureTools::onOpacitySliderChange, this);
|
|
m_tolerance->Change.connect(&ConfigureTools::onToleranceSliderChange, this);
|
|
m_airSpeed->Change.connect(&ConfigureTools::onAirSpeedSliderChange, this);
|
|
m_sprayWidth->Change.connect(&ConfigureTools::onSprayWidthSliderChange, this);
|
|
m_brushType->ItemChange.connect(&ConfigureTools::onBrushTypeChange, this);
|
|
}
|
|
|
|
// Update current pen properties
|
|
on_current_tool_change();
|
|
|
|
// Default position
|
|
window->remapWindow();
|
|
window->centerWindow();
|
|
|
|
// Load window configuration
|
|
load_window_pos(window, "ConfigureTool");
|
|
|
|
window->openWindow();
|
|
}
|
|
|
|
void ConfigureTools::onWindowClose()
|
|
{
|
|
save_window_pos(window, "ConfigureTool");
|
|
}
|
|
|
|
void ConfigureTools::onBrushTypeChange()
|
|
{
|
|
PenType type = (PenType)m_brushType->getSelectedItem();
|
|
|
|
Tool* current_tool = m_settings->getCurrentTool();
|
|
m_settings->getToolSettings(current_tool)
|
|
->getPen()
|
|
->setType(type);
|
|
|
|
m_brushPreview->invalidate();
|
|
|
|
StatusBar::instance()
|
|
->setStatusText(250,
|
|
"Pen shape: %s",
|
|
type == PEN_TYPE_CIRCLE ? "Circle":
|
|
type == PEN_TYPE_SQUARE ? "Square":
|
|
type == PEN_TYPE_LINE ? "Line": "Unknown");
|
|
}
|
|
|
|
void ConfigureTools::onBrushSizeSliderChange()
|
|
{
|
|
Tool* current_tool = m_settings->getCurrentTool();
|
|
m_settings->getToolSettings(current_tool)
|
|
->getPen()
|
|
->setSize(m_brushSize->getValue());
|
|
|
|
m_brushPreview->invalidate();
|
|
}
|
|
|
|
void ConfigureTools::onBrushAngleSliderChange()
|
|
{
|
|
Tool* current_tool = m_settings->getCurrentTool();
|
|
m_settings->getToolSettings(current_tool)
|
|
->getPen()
|
|
->setAngle(m_brushAngle->getValue());
|
|
|
|
m_brushPreview->invalidate();
|
|
}
|
|
|
|
void ConfigureTools::onOpacitySliderChange()
|
|
{
|
|
Tool* current_tool = m_settings->getCurrentTool();
|
|
|
|
m_settings->getToolSettings(current_tool)->setOpacity(m_opacity->getValue());
|
|
}
|
|
|
|
void ConfigureTools::onToleranceSliderChange()
|
|
{
|
|
Tool* current_tool = m_settings->getCurrentTool();
|
|
|
|
m_settings->getToolSettings(current_tool)->setTolerance(m_tolerance->getValue());
|
|
}
|
|
|
|
void ConfigureTools::onSprayWidthSliderChange()
|
|
{
|
|
Tool* current_tool = m_settings->getCurrentTool();
|
|
|
|
m_settings->getToolSettings(current_tool)->setSprayWidth(m_sprayWidth->getValue());
|
|
}
|
|
|
|
void ConfigureTools::onAirSpeedSliderChange()
|
|
{
|
|
Tool* current_tool = m_settings->getCurrentTool();
|
|
|
|
m_settings->getToolSettings(current_tool)->setSpraySpeed(m_airSpeed->getValue());
|
|
}
|
|
|
|
void ConfigureTools::onTiledClick()
|
|
{
|
|
bool flag = m_tiled->isSelected();
|
|
|
|
m_docSettings->setTiledMode(flag ? TILED_BOTH: TILED_NONE);
|
|
|
|
m_tiledX->setSelected(flag);
|
|
m_tiledY->setSelected(flag);
|
|
}
|
|
|
|
void ConfigureTools::onTiledXYClick(int tiled_axis, CheckBox* checkbox)
|
|
{
|
|
int tiled_mode = m_docSettings->getTiledMode();
|
|
|
|
if (checkbox->isSelected())
|
|
tiled_mode |= tiled_axis;
|
|
else
|
|
tiled_mode &= ~tiled_axis;
|
|
|
|
checkbox->findSibling("tiled")->setSelected(tiled_mode != TILED_NONE);
|
|
|
|
m_docSettings->setTiledMode((TiledMode)tiled_mode);
|
|
}
|
|
|
|
void ConfigureTools::onSnapToGridClick()
|
|
{
|
|
m_docSettings->setSnapToGrid(m_snapToGrid->isSelected());
|
|
}
|
|
|
|
void ConfigureTools::onViewGridClick()
|
|
{
|
|
m_docSettings->setGridVisible(m_viewGrid->isSelected());
|
|
}
|
|
|
|
void ConfigureTools::onPixelGridClick()
|
|
{
|
|
m_docSettings->setPixelGridVisible(m_pixelGrid->isSelected());
|
|
}
|
|
|
|
void ConfigureTools::onSetGridClick()
|
|
{
|
|
try {
|
|
// TODO use the same context as in ConfigureTools::onExecute
|
|
const ActiveDocumentReader document(UIContext::instance());
|
|
|
|
if (document && document->isMaskVisible()) {
|
|
const Mask* mask(document->getMask());
|
|
|
|
m_docSettings->setGridBounds(mask->getBounds());
|
|
}
|
|
else {
|
|
Command* grid_settings_cmd =
|
|
CommandsModule::instance()->getCommandByName(CommandId::GridSettings);
|
|
|
|
UIContext::instance()->executeCommand(grid_settings_cmd, NULL);
|
|
}
|
|
}
|
|
catch (LockedDocumentException& e) {
|
|
Console::showException(e);
|
|
}
|
|
}
|
|
|
|
void ConfigureTools::onOnionSkinClick()
|
|
{
|
|
m_docSettings->setUseOnionskin(m_onionSkin->isSelected());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// CommandFactory
|
|
|
|
Command* CommandFactory::createConfigureToolsCommand()
|
|
{
|
|
return new ConfigureTools;
|
|
}
|