mirror of
https://github.com/aseprite/aseprite.git
synced 2025-04-10 03:44:16 +00:00
Refactor Editor class to use a state design pattern.
+ Added EditorState and derived classes (StandByState, DrawingState, etc.) + Added StatusBarListener.
This commit is contained in:
parent
ef0cbf0e94
commit
5380877c4a
@ -281,11 +281,16 @@ add_library(aseprite-library
|
||||
widgets/color_sliders.cpp
|
||||
widgets/editor/click.cpp
|
||||
widgets/editor/cursor.cpp
|
||||
widgets/editor/drawing_state.cpp
|
||||
widgets/editor/editor.cpp
|
||||
widgets/editor/editor_listeners.cpp
|
||||
widgets/editor/editor_view.cpp
|
||||
widgets/editor/keys.cpp
|
||||
widgets/editor/moving_pixels_state.cpp
|
||||
widgets/editor/pixels_movement.cpp
|
||||
widgets/editor/scrolling_state.cpp
|
||||
widgets/editor/standby_state.cpp
|
||||
widgets/editor/tool_loop_impl.cpp
|
||||
widgets/fileview.cpp
|
||||
widgets/groupbut.cpp
|
||||
widgets/hex_color_entry.cpp
|
||||
|
@ -59,7 +59,7 @@ void GotoFirstFrameCommand::onExecute(Context* context)
|
||||
sprite->setCurrentFrame(0);
|
||||
|
||||
update_screen_for_document(document);
|
||||
current_editor->editor_update_statusbar_for_standby();
|
||||
current_editor->updateStatusBar();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -101,7 +101,7 @@ void GotoPreviousFrameCommand::onExecute(Context* context)
|
||||
sprite->setCurrentFrame(sprite->getTotalFrames()-1);
|
||||
|
||||
update_screen_for_document(document);
|
||||
current_editor->editor_update_statusbar_for_standby();
|
||||
current_editor->updateStatusBar();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -143,7 +143,7 @@ void GotoNextFrameCommand::onExecute(Context* context)
|
||||
sprite->setCurrentFrame(0);
|
||||
|
||||
update_screen_for_document(document);
|
||||
current_editor->editor_update_statusbar_for_standby();
|
||||
current_editor->updateStatusBar();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
@ -180,7 +180,7 @@ void GotoLastFrameCommand::onExecute(Context* context)
|
||||
sprite->setCurrentFrame(sprite->getTotalFrames()-1);
|
||||
|
||||
update_screen_for_document(document);
|
||||
current_editor->editor_update_statusbar_for_standby();
|
||||
current_editor->updateStatusBar();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -117,9 +117,12 @@ public:
|
||||
}
|
||||
|
||||
void documentChanged(Editor* editor) OVERRIDE {
|
||||
if (editor == current_editor) {
|
||||
if (editor == current_editor)
|
||||
update_mini_editor_frame(editor);
|
||||
}
|
||||
}
|
||||
|
||||
void stateChanged(Editor* editor) OVERRIDE {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
};
|
||||
@ -133,6 +136,7 @@ void exit_module_editors()
|
||||
{
|
||||
if (mini_editor_frame) {
|
||||
save_window_pos(mini_editor_frame, "MiniEditor");
|
||||
|
||||
delete mini_editor_frame;
|
||||
mini_editor_frame = NULL;
|
||||
}
|
||||
@ -590,6 +594,7 @@ static void update_mini_editor_frame(Editor* editor)
|
||||
if (mini_editor->getDocument() != document) {
|
||||
mini_editor->setDocument(document);
|
||||
mini_editor->setZoom(0);
|
||||
mini_editor->setState(new EditorState);
|
||||
}
|
||||
|
||||
mini_editor->centerInSpritePoint(pt.x, pt.y);
|
||||
|
@ -41,7 +41,7 @@ class PointShape;
|
||||
class Tool;
|
||||
|
||||
// Interface to communicate the sprite editor with the tool when the user
|
||||
// start using a tool to paint, select, pick color, etc.
|
||||
// starts using a tool to paint, select, pick color, etc.
|
||||
//
|
||||
// All this information should be provided by the editor and consumed
|
||||
// by the tool (+controller+intertwiner+pointshape+ink).
|
||||
|
@ -39,7 +39,6 @@ ToolLoopManager::ToolLoopManager(ToolLoop* toolLoop)
|
||||
|
||||
ToolLoopManager::~ToolLoopManager()
|
||||
{
|
||||
delete m_toolLoop;
|
||||
}
|
||||
|
||||
bool ToolLoopManager::isCanceled() const
|
||||
|
@ -279,8 +279,7 @@ void Editor::editor_draw_cursor(int x, int y, bool refresh)
|
||||
generate_cursor_boundaries();
|
||||
|
||||
// draw pixel/pen preview
|
||||
if (cursor_type & CURSOR_PENCIL &&
|
||||
m_state != EDITOR_STATE_DRAWING) {
|
||||
if (cursor_type & CURSOR_PENCIL && m_state->requirePenPreview()) {
|
||||
IToolSettings* tool_settings = UIContext::instance()
|
||||
->getSettings()
|
||||
->getToolSettings(current_tool);
|
||||
@ -364,8 +363,7 @@ void Editor::editor_move_cursor(int x, int y, bool refresh)
|
||||
ji_screen->clip = TRUE;
|
||||
release_bitmap(ji_screen);
|
||||
|
||||
if (cursor_type & CURSOR_PENCIL &&
|
||||
m_state != EDITOR_STATE_DRAWING) {
|
||||
if (cursor_type & CURSOR_PENCIL && m_state->requirePenPreview()) {
|
||||
Pen* pen = editor_get_current_pen();
|
||||
editors_draw_sprite(m_sprite,
|
||||
std::min(new_x, old_x)-pen->get_size()/2,
|
||||
@ -420,8 +418,7 @@ void Editor::editor_clean_cursor(bool refresh)
|
||||
}
|
||||
|
||||
// clean pixel/pen preview
|
||||
if (cursor_type & CURSOR_PENCIL &&
|
||||
m_state != EDITOR_STATE_DRAWING) {
|
||||
if (cursor_type & CURSOR_PENCIL && m_state->requirePenPreview()) {
|
||||
Pen* pen = editor_get_current_pen();
|
||||
|
||||
m_document->prepareExtraCel(x-pen->get_size()/2,
|
||||
|
165
src/widgets/editor/drawing_state.cpp
Normal file
165
src/widgets/editor/drawing_state.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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 "widgets/editor/drawing_state.h"
|
||||
|
||||
#include "gui/message.h"
|
||||
#include "gui/system.h"
|
||||
#include "tools/ink.h"
|
||||
#include "tools/tool.h"
|
||||
#include "tools/tool_loop.h"
|
||||
#include "tools/tool_loop_manager.h"
|
||||
#include "widgets/editor/editor.h"
|
||||
#include "widgets/editor/standby_state.h"
|
||||
|
||||
#include <allegro.h>
|
||||
|
||||
static tools::ToolLoopManager::Pointer pointer_from_msg(Message* msg)
|
||||
{
|
||||
tools::ToolLoopManager::Pointer::Button button =
|
||||
(msg->mouse.right ? tools::ToolLoopManager::Pointer::Right:
|
||||
(msg->mouse.middle ? tools::ToolLoopManager::Pointer::Middle:
|
||||
tools::ToolLoopManager::Pointer::Left));
|
||||
|
||||
return tools::ToolLoopManager::Pointer(msg->mouse.x, msg->mouse.y, button);
|
||||
}
|
||||
|
||||
DrawingState::DrawingState(tools::ToolLoop* toolLoop, Editor* editor, Message* msg)
|
||||
: m_toolLoop(toolLoop)
|
||||
, m_toolLoopManager(new tools::ToolLoopManager(toolLoop))
|
||||
{
|
||||
// Hide the cursor (mainly to clean the pen preview)
|
||||
editor->hideDrawingCursor();
|
||||
|
||||
m_toolLoopManager->prepareLoop(pointer_from_msg(msg));
|
||||
m_toolLoopManager->pressButton(pointer_from_msg(msg));
|
||||
|
||||
// Show drawing cursor again (without pen preview in this case)
|
||||
editor->showDrawingCursor();
|
||||
|
||||
editor->captureMouse();
|
||||
}
|
||||
|
||||
DrawingState::~DrawingState()
|
||||
{
|
||||
delete m_toolLoopManager;
|
||||
delete m_toolLoop;
|
||||
m_toolLoopManager = NULL;
|
||||
m_toolLoop = NULL;
|
||||
}
|
||||
|
||||
bool DrawingState::onMouseDown(Editor* editor, Message* msg)
|
||||
{
|
||||
// Drawing loop
|
||||
ASSERT(m_toolLoopManager != NULL);
|
||||
|
||||
// Notify the mouse button down to the tool loop manager.
|
||||
m_toolLoopManager->pressButton(pointer_from_msg(msg));
|
||||
|
||||
// Cancel drawing loop
|
||||
if (m_toolLoopManager->isCanceled()) {
|
||||
m_toolLoopManager->releaseLoop(pointer_from_msg(msg));
|
||||
|
||||
delete m_toolLoopManager;
|
||||
m_toolLoopManager = NULL;
|
||||
|
||||
// Change to standby state
|
||||
editor->setState(new StandbyState());
|
||||
editor->releaseMouse();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrawingState::onMouseUp(Editor* editor, Message* msg)
|
||||
{
|
||||
ASSERT(m_toolLoopManager != NULL);
|
||||
|
||||
// Notify the release of the mouse button to the tool loop manager.
|
||||
if (m_toolLoopManager->releaseButton(pointer_from_msg(msg)))
|
||||
return true;
|
||||
|
||||
m_toolLoopManager->releaseLoop(pointer_from_msg(msg));
|
||||
|
||||
// Back to standby state.
|
||||
editor->setState(new StandbyState);
|
||||
editor->releaseMouse();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrawingState::onMouseMove(Editor* editor, Message* msg)
|
||||
{
|
||||
ASSERT(m_toolLoopManager != NULL);
|
||||
|
||||
acquire_bitmap(ji_screen);
|
||||
|
||||
// Hide the drawing cursor
|
||||
editor->hideDrawingCursor();
|
||||
|
||||
// Infinite scroll
|
||||
editor->controlInfiniteScroll(msg);
|
||||
|
||||
// Hide the cursor again
|
||||
editor->hideDrawingCursor();
|
||||
|
||||
// notify mouse movement to the tool
|
||||
ASSERT(m_toolLoopManager != NULL);
|
||||
m_toolLoopManager->movement(pointer_from_msg(msg));
|
||||
|
||||
// draw the cursor again
|
||||
editor->showDrawingCursor();
|
||||
|
||||
release_bitmap(ji_screen);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrawingState::onSetCursor(Editor* editor)
|
||||
{
|
||||
if (m_toolLoop->getInk()->isEyedropper()) {
|
||||
editor->hideDrawingCursor();
|
||||
jmouse_set_cursor(JI_CURSOR_EYEDROPPER);
|
||||
}
|
||||
else {
|
||||
jmouse_set_cursor(JI_CURSOR_NULL);
|
||||
editor->showDrawingCursor();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrawingState::onKeyDown(Editor* editor, Message* msg)
|
||||
{
|
||||
if (editor->processKeysToSetZoom(msg->key.scancode))
|
||||
return true;
|
||||
|
||||
// When we are drawing, we "eat" all pressed keys.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrawingState::onKeyUp(Editor* editor, Message* msg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrawingState::onUpdateStatusBar(Editor* editor)
|
||||
{
|
||||
// The status bar is updated by ToolLoopImpl::updateStatusBar()
|
||||
// method called by the ToolLoopManager.
|
||||
return false;
|
||||
}
|
55
src/widgets/editor/drawing_state.h
Normal file
55
src/widgets/editor/drawing_state.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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
|
||||
*/
|
||||
|
||||
#ifndef WIDGETS_EDITOR_DRAWING_STATE_H_INCLUDED
|
||||
#define WIDGETS_EDITOR_DRAWING_STATE_H_INCLUDED
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "widgets/editor/standby_state.h"
|
||||
|
||||
namespace tools {
|
||||
class ToolLoop;
|
||||
class ToolLoopManager;
|
||||
}
|
||||
|
||||
class DrawingState : public StandbyState
|
||||
{
|
||||
public:
|
||||
DrawingState(tools::ToolLoop* loop, Editor* editor, Message* msg);
|
||||
virtual ~DrawingState();
|
||||
virtual bool onMouseDown(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseUp(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseMove(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onSetCursor(Editor* editor) OVERRIDE;
|
||||
virtual bool onKeyDown(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onKeyUp(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) OVERRIDE;
|
||||
|
||||
// Drawing state doesn't require the pen-preview because we are
|
||||
// already drawing (viewing the real trace).
|
||||
virtual bool requirePenPreview() OVERRIDE { return false; }
|
||||
|
||||
private:
|
||||
// The tool-loop.
|
||||
tools::ToolLoop* m_toolLoop;
|
||||
|
||||
// Tool-loop manager
|
||||
tools::ToolLoopManager* m_toolLoopManager;
|
||||
};
|
||||
|
||||
#endif // WIDGETS_EDITOR_DRAWING_STATE_H_INCLUDED
|
File diff suppressed because it is too large
Load Diff
@ -26,6 +26,7 @@
|
||||
#include "gui/base.h"
|
||||
#include "gui/widget.h"
|
||||
#include "widgets/editor/editor_listeners.h"
|
||||
#include "widgets/editor/editor_state.h"
|
||||
|
||||
#define MIN_ZOOM 0
|
||||
#define MAX_ZOOM 5
|
||||
@ -37,8 +38,6 @@ class View;
|
||||
|
||||
namespace tools {
|
||||
class Tool;
|
||||
class ToolLoop;
|
||||
class ToolLoopManager;
|
||||
}
|
||||
|
||||
class Editor : public Widget
|
||||
@ -49,6 +48,11 @@ public:
|
||||
Editor();
|
||||
~Editor();
|
||||
|
||||
EditorState* getState() const { return m_state; }
|
||||
|
||||
// Changes the state of the editor. Deletes the old state.
|
||||
void setState(EditorState* state);
|
||||
|
||||
Document* getDocument() { return m_document; }
|
||||
void setDocument(Document* document);
|
||||
|
||||
@ -81,13 +85,13 @@ public:
|
||||
void drawMaskSafe();
|
||||
|
||||
void flashCurrentLayer();
|
||||
void setMaskColorForPixelsMovement(const Color& color);
|
||||
|
||||
void screenToEditor(int xin, int yin, int *xout, int *yout);
|
||||
void editorToScreen(int xin, int yin, int *xout, int *yout);
|
||||
|
||||
void showDrawingCursor();
|
||||
void hideDrawingCursor();
|
||||
void moveDrawingCursor();
|
||||
|
||||
void addListener(EditorListener* listener);
|
||||
void removeListener(EditorListener* listener);
|
||||
@ -97,8 +101,23 @@ public:
|
||||
|
||||
// Changes the scroll to see the given point as the center of the editor.
|
||||
void centerInSpritePoint(int x, int y);
|
||||
|
||||
void updateStatusBar();
|
||||
|
||||
void editor_update_statusbar_for_standby();
|
||||
// Control scroll when cursor goes out of the editor.
|
||||
void controlInfiniteScroll(Message* msg);
|
||||
|
||||
tools::Tool* getCurrentEditorTool();
|
||||
|
||||
// Returns true if we are able to draw in the current doc/sprite/layer/cel.
|
||||
bool canDraw();
|
||||
|
||||
// Returns true if the cursor is inside the active mask/selection.
|
||||
bool isInsideSelection();
|
||||
|
||||
void setZoomAndCenterInMouse(int zoom, int mouse_x, int mouse_y);
|
||||
|
||||
bool processKeysToSetZoom(int scancode);
|
||||
|
||||
// in cursor.c
|
||||
|
||||
@ -111,19 +130,12 @@ public:
|
||||
static void editor_cursor_exit();
|
||||
|
||||
private:
|
||||
|
||||
void editor_update_statusbar_for_pixel_movement();
|
||||
void editor_update_quicktool();
|
||||
|
||||
void editor_draw_cursor(int x, int y, bool refresh = true);
|
||||
void editor_move_cursor(int x, int y, bool refresh = true);
|
||||
void editor_clean_cursor(bool refresh = true);
|
||||
bool editor_cursor_is_subpixel();
|
||||
|
||||
// keys.c
|
||||
|
||||
bool editor_keys_toset_zoom(int scancode);
|
||||
|
||||
public:
|
||||
|
||||
// click.c
|
||||
@ -147,45 +159,27 @@ protected:
|
||||
private:
|
||||
void drawGrid(const gfx::Rect& gridBounds, const Color& color);
|
||||
|
||||
void controlInfiniteScroll(Message* msg);
|
||||
void dropPixels();
|
||||
|
||||
tools::Tool* getCurrentEditorTool();
|
||||
|
||||
void editor_request_size(int *w, int *h);
|
||||
void editor_setcursor(int x, int y);
|
||||
void editor_update_candraw();
|
||||
void setZoomAndCenterInMouse(int zoom, int mouse_x, int mouse_y);
|
||||
|
||||
tools::ToolLoop* createToolLoopImpl(Context* context, Message* msg);
|
||||
void editor_setcursor();
|
||||
|
||||
void for_each_pixel_of_pen(int screen_x, int screen_y,
|
||||
int sprite_x, int sprite_y, int color,
|
||||
void (*pixel)(BITMAP *bmp, int x, int y, int color));
|
||||
|
||||
// editor states
|
||||
enum State {
|
||||
EDITOR_STATE_STANDBY,
|
||||
EDITOR_STATE_SCROLLING,
|
||||
EDITOR_STATE_DRAWING,
|
||||
};
|
||||
|
||||
// Main properties
|
||||
State m_state; // Editor main state
|
||||
// Current editor state (it can be shared between several editors to
|
||||
// the same document). This member cannot be NULL.
|
||||
EditorState* m_state;
|
||||
|
||||
Document* m_document; // Active document in the editor
|
||||
Sprite* m_sprite; // Active sprite in the editor
|
||||
int m_zoom; // Zoom in the editor
|
||||
|
||||
// Drawing cursor
|
||||
int m_cursor_thick;
|
||||
int m_cursor_screen_x; /* position in the screen (view) */
|
||||
int m_cursor_screen_x; // Position in the screen (view)
|
||||
int m_cursor_screen_y;
|
||||
int m_cursor_editor_x; /* position in the editor (model) */
|
||||
int m_cursor_editor_x; // Position in the editor (model)
|
||||
int m_cursor_editor_y;
|
||||
bool m_cursor_candraw : 1;
|
||||
|
||||
// True if the cursor is inside the mask/selection
|
||||
bool m_insideSelection : 1;
|
||||
|
||||
// Current selected quicktool (this genererally should be NULL if
|
||||
// the user is not pressing any keyboard key).
|
||||
@ -195,20 +189,10 @@ private:
|
||||
int m_offset_x;
|
||||
int m_offset_y;
|
||||
|
||||
/* marching ants stuff */
|
||||
// Marching ants stuff
|
||||
int m_mask_timer_id;
|
||||
int m_offset_count;
|
||||
|
||||
/* region that must be updated */
|
||||
JRegion m_refresh_region;
|
||||
|
||||
// Tool-loop manager
|
||||
tools::ToolLoopManager* m_toolLoopManager;
|
||||
|
||||
// Helper member to move selection. If this member is NULL it means the
|
||||
// user is not moving pixels.
|
||||
PixelsMovement* m_pixelsMovement;
|
||||
|
||||
// This slot is used to disconnect the Editor from CurrentToolChange
|
||||
// signal (because the editor can be destroyed and the application
|
||||
// still continue running and generating CurrentToolChange
|
||||
|
@ -26,7 +26,14 @@ class EditorListener
|
||||
public:
|
||||
virtual ~EditorListener() { }
|
||||
virtual void dispose() = 0;
|
||||
|
||||
// Called when the editor's state changes.
|
||||
virtual void stateChanged(Editor* editor) = 0;
|
||||
|
||||
// Called when the scroll or zoom of the editor changes.
|
||||
virtual void scrollChanged(Editor* editor) = 0;
|
||||
|
||||
// Called when the document shown in the editor changes.
|
||||
virtual void documentChanged(Editor* editor) = 0;
|
||||
};
|
||||
|
||||
|
@ -37,6 +37,11 @@ void EditorListeners::removeListener(EditorListener* listener)
|
||||
m_listeners.removeListener(listener);
|
||||
}
|
||||
|
||||
void EditorListeners::notifyStateChanged(Editor* editor)
|
||||
{
|
||||
m_listeners.notify(&EditorListener::stateChanged, editor);
|
||||
}
|
||||
|
||||
void EditorListeners::notifyScrollChanged(Editor* editor)
|
||||
{
|
||||
m_listeners.notify(&EditorListener::scrollChanged, editor);
|
||||
|
@ -32,6 +32,7 @@ public:
|
||||
void addListener(EditorListener* listener);
|
||||
void removeListener(EditorListener* listener);
|
||||
|
||||
void notifyStateChanged(Editor* editor);
|
||||
void notifyScrollChanged(Editor* editor);
|
||||
void notifyDocumentChanged(Editor* editor);
|
||||
|
||||
|
81
src/widgets/editor/editor_state.h
Normal file
81
src/widgets/editor/editor_state.h
Normal file
@ -0,0 +1,81 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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
|
||||
*/
|
||||
|
||||
#ifndef WIDGETS_EDITOR_EDITOR_STATE_H_INCLUDED
|
||||
#define WIDGETS_EDITOR_EDITOR_STATE_H_INCLUDED
|
||||
|
||||
class Editor;
|
||||
union Message;
|
||||
|
||||
// Represents one state of the sprite's editor (Editor class). This
|
||||
// is a base class, a dummy state that ignores all events from the
|
||||
// Editor. Subclasses overrides these methods to customize the
|
||||
// behavior of the Editor to do different tasks (e.g. scrolling,
|
||||
// drawing in the active sprite, etc.).
|
||||
class EditorState
|
||||
{
|
||||
public:
|
||||
virtual ~EditorState() { }
|
||||
|
||||
// Called just before this state is deleted and replaced by a new
|
||||
// state in the Editor::setState() method.
|
||||
virtual void onBeforeChangeState(Editor* editor) { }
|
||||
|
||||
// Called when this instance is set as the new Editor's state when
|
||||
// Editor::setState() method is used.
|
||||
virtual void onAfterChangeState(Editor* editor) { }
|
||||
|
||||
// Called when the current tool in the tool bar changes. It is
|
||||
// useful for states which depends on the selected current tool (as
|
||||
// MovingPixelsState which drops the pixels in case the user selects
|
||||
// other drawing tool).
|
||||
virtual void onCurrentToolChange(Editor* editor) { }
|
||||
|
||||
// Called when the user presses a mouse button over the editor.
|
||||
virtual bool onMouseDown(Editor* editor, Message* msg) { return false; }
|
||||
|
||||
// Called when the user releases a mouse button.
|
||||
virtual bool onMouseUp(Editor* editor, Message* msg) { return false; }
|
||||
|
||||
// Called when the user moves the mouse over the editor.
|
||||
virtual bool onMouseMove(Editor* editor, Message* msg) { return false; }
|
||||
|
||||
// Called when the user moves the mouse wheel over the editor.
|
||||
virtual bool onMouseWheel(Editor* editor, Message* msg) { return false; }
|
||||
|
||||
// Called each time the mouse changes its position so we can set an
|
||||
// appropiated cursor depending on the new coordinates of the mouse
|
||||
// pointer.
|
||||
virtual bool onSetCursor(Editor* editor) { return false; }
|
||||
|
||||
// Called when a key is pressed over the current editor.
|
||||
virtual bool onKeyDown(Editor* editor, Message* msg) { return false; }
|
||||
|
||||
// Called when a key is released.
|
||||
virtual bool onKeyUp(Editor* editor, Message* msg) { return false; }
|
||||
|
||||
// Called when a key is released.
|
||||
virtual bool onUpdateStatusBar(Editor* editor) { return false; }
|
||||
|
||||
// Returns true if the this state requires the pen-preview as
|
||||
// drawing cursor.
|
||||
virtual bool requirePenPreview() { return false; }
|
||||
|
||||
};
|
||||
|
||||
#endif // WIDGETS_EDITOR_EDITOR_STATE_H_INCLUDED
|
@ -35,7 +35,7 @@
|
||||
#include "widgets/color_bar.h"
|
||||
#include "widgets/editor/editor.h"
|
||||
|
||||
bool Editor::editor_keys_toset_zoom(int scancode)
|
||||
bool Editor::processKeysToSetZoom(int scancode)
|
||||
{
|
||||
if ((m_sprite) &&
|
||||
(this->hasMouse()) &&
|
||||
|
274
src/widgets/editor/moving_pixels_state.cpp
Normal file
274
src/widgets/editor/moving_pixels_state.cpp
Normal file
@ -0,0 +1,274 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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 "widgets/editor/moving_pixels_state.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "app/color_utils.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "gui/message.h"
|
||||
#include "gui/system.h"
|
||||
#include "gui/view.h"
|
||||
#include "modules/editors.h"
|
||||
#include "raster/mask.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "tools/ink.h"
|
||||
#include "tools/tool.h"
|
||||
#include "util/misc.h"
|
||||
#include "widgets/editor/editor.h"
|
||||
#include "widgets/editor/pixels_movement.h"
|
||||
#include "widgets/editor/standby_state.h"
|
||||
#include "widgets/statebar.h"
|
||||
|
||||
#include <allegro.h>
|
||||
|
||||
MovingPixelsState::MovingPixelsState(Editor* editor, Message* msg, Image* imge, int x, int y, int opacity)
|
||||
{
|
||||
// Copy the mask to the extra cel image
|
||||
Document* document = editor->getDocument();
|
||||
Sprite* sprite = editor->getSprite();
|
||||
Image* tmpImage = NewImageFromMask(document);
|
||||
x = document->getMask()->x;
|
||||
y = document->getMask()->y;
|
||||
m_pixelsMovement = new PixelsMovement(document, sprite, tmpImage, x, y, opacity);
|
||||
delete tmpImage;
|
||||
|
||||
// If the CTRL key is pressed start dragging a copy of the selection
|
||||
if (key[KEY_LCONTROL] || key[KEY_RCONTROL]) // TODO configurable
|
||||
m_pixelsMovement->copyMask();
|
||||
else
|
||||
m_pixelsMovement->cutMask();
|
||||
|
||||
editor->screenToEditor(msg->mouse.x, msg->mouse.y, &x, &y);
|
||||
m_pixelsMovement->catchImage(x, y);
|
||||
|
||||
// Setup mask color
|
||||
setTransparentColor(app_get_statusbar()->getTransparentColor());
|
||||
|
||||
app_get_statusbar()->addListener(this);
|
||||
app_get_statusbar()->showMovePixelsOptions();
|
||||
|
||||
editor->captureMouse();
|
||||
}
|
||||
|
||||
MovingPixelsState::~MovingPixelsState()
|
||||
{
|
||||
app_get_statusbar()->removeListener(this);
|
||||
|
||||
delete m_pixelsMovement;
|
||||
}
|
||||
|
||||
void MovingPixelsState::onBeforeChangeState(Editor* editor)
|
||||
{
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
// If we are changing to another state, we've to drop the image.
|
||||
if (m_pixelsMovement->isDragging())
|
||||
m_pixelsMovement->dropImageTemporarily();
|
||||
|
||||
// Drop pixels if the user press a button outside the selection
|
||||
m_pixelsMovement->dropImage();
|
||||
delete m_pixelsMovement;
|
||||
m_pixelsMovement = NULL;
|
||||
|
||||
editor->releaseMouse();
|
||||
|
||||
app_get_statusbar()->hideMovePixelsOptions();
|
||||
}
|
||||
|
||||
void MovingPixelsState::onCurrentToolChange(Editor* editor)
|
||||
{
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
tools::Tool* current_tool = editor->getCurrentEditorTool();
|
||||
|
||||
// If the user changed the tool when he/she is moving pixels,
|
||||
// we have to drop the pixels only if the new tool is not selection...
|
||||
if (m_pixelsMovement &&
|
||||
(!current_tool->getInk(0)->isSelection() ||
|
||||
!current_tool->getInk(1)->isSelection())) {
|
||||
// We have to drop pixels
|
||||
dropPixels(editor);
|
||||
}
|
||||
}
|
||||
|
||||
bool MovingPixelsState::onMouseDown(Editor* editor, Message* msg)
|
||||
{
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
// Start "moving pixels" loop
|
||||
if (editor->isInsideSelection() && (msg->mouse.left ||
|
||||
msg->mouse.right)) {
|
||||
// Re-catch the image
|
||||
int x, y;
|
||||
editor->screenToEditor(msg->mouse.x, msg->mouse.y, &x, &y);
|
||||
m_pixelsMovement->catchImageAgain(x, y);
|
||||
|
||||
editor->captureMouse();
|
||||
return true;
|
||||
}
|
||||
// End "moving pixels" loop
|
||||
else {
|
||||
// Drop pixels (e.g. to start drawing)
|
||||
dropPixels(editor);
|
||||
}
|
||||
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onMouseDown(editor, msg);
|
||||
}
|
||||
|
||||
bool MovingPixelsState::onMouseUp(Editor* editor, Message* msg)
|
||||
{
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
// Drop the image temporarily in this location (where the user releases the mouse)
|
||||
m_pixelsMovement->dropImageTemporarily();
|
||||
|
||||
editor->releaseMouse();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MovingPixelsState::onMouseMove(Editor* editor, Message* msg)
|
||||
{
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
// If there is a button pressed
|
||||
if (m_pixelsMovement->isDragging()) {
|
||||
// Infinite scroll
|
||||
editor->controlInfiniteScroll(msg);
|
||||
|
||||
// Get the position of the mouse in the sprite
|
||||
int x, y;
|
||||
editor->screenToEditor(msg->mouse.x, msg->mouse.y, &x, &y);
|
||||
|
||||
// Drag the image to that position
|
||||
gfx::Rect bounds = m_pixelsMovement->moveImage(x, y);
|
||||
|
||||
// If "bounds" is empty is because the cel was not moved
|
||||
if (!bounds.isEmpty()) {
|
||||
// Redraw the extra cel in the new position
|
||||
jmouse_hide();
|
||||
editors_draw_sprite_tiled(editor->getSprite(),
|
||||
bounds.x, bounds.y,
|
||||
bounds.x+bounds.w-1,
|
||||
bounds.y+bounds.h-1);
|
||||
jmouse_show();
|
||||
}
|
||||
editor->updateStatusBar();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onMouseMove(editor, msg);
|
||||
}
|
||||
|
||||
bool MovingPixelsState::onMouseWheel(Editor* editor, Message* msg)
|
||||
{
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onMouseWheel(editor, msg);
|
||||
}
|
||||
|
||||
bool MovingPixelsState::onSetCursor(Editor* editor)
|
||||
{
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
// Move selection
|
||||
if (m_pixelsMovement->isDragging() || editor->isInsideSelection()) {
|
||||
editor->hideDrawingCursor();
|
||||
jmouse_set_cursor(JI_CURSOR_MOVE);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onSetCursor(editor);
|
||||
}
|
||||
|
||||
bool MovingPixelsState::onKeyDown(Editor* editor, Message* msg)
|
||||
{
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
if (msg->key.scancode == KEY_LCONTROL || // TODO configurable
|
||||
msg->key.scancode == KEY_RCONTROL) {
|
||||
// If the user press the CTRL key when he is dragging pixels (but
|
||||
// not pressing the mouse buttons).
|
||||
if (!jmouse_b(0) && m_pixelsMovement) {
|
||||
// Drop pixels (sure the user will press the mouse button to
|
||||
// start dragging a copy).
|
||||
dropPixels(editor);
|
||||
}
|
||||
}
|
||||
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onKeyDown(editor, msg);
|
||||
}
|
||||
|
||||
bool MovingPixelsState::onKeyUp(Editor* editor, Message* msg)
|
||||
{
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onKeyUp(editor, msg);
|
||||
}
|
||||
|
||||
bool MovingPixelsState::onUpdateStatusBar(Editor* editor)
|
||||
{
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
gfx::Rect bounds = m_pixelsMovement->getImageBounds();
|
||||
|
||||
app_get_statusbar()->setStatusText
|
||||
(100, "Pos %d %d, Size %d %d",
|
||||
bounds.x, bounds.y, bounds.w, bounds.h);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MovingPixelsState::dispose()
|
||||
{
|
||||
// Never called as MovingPixelsState is removed automatically as
|
||||
// StatusBar's listener.
|
||||
}
|
||||
|
||||
void MovingPixelsState::onChangeTransparentColor(const Color& color)
|
||||
{
|
||||
setTransparentColor(color);
|
||||
}
|
||||
|
||||
void MovingPixelsState::setTransparentColor(const Color& color)
|
||||
{
|
||||
ASSERT(current_editor != NULL);
|
||||
ASSERT(m_pixelsMovement != NULL);
|
||||
|
||||
Sprite* sprite = current_editor->getSprite();
|
||||
ASSERT(sprite != NULL);
|
||||
|
||||
int imgtype = sprite->getImgType();
|
||||
m_pixelsMovement->setMaskColor(color_utils::color_for_image(color, imgtype));
|
||||
}
|
||||
|
||||
void MovingPixelsState::dropPixels(Editor* editor)
|
||||
{
|
||||
// Just change to standby state (we'll receive an
|
||||
// onBeforeChangeState event).
|
||||
editor->setState(new StandbyState);
|
||||
}
|
||||
|
60
src/widgets/editor/moving_pixels_state.h
Normal file
60
src/widgets/editor/moving_pixels_state.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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
|
||||
*/
|
||||
|
||||
#ifndef WIDGETS_EDITOR_MOVING_PIXELS_STATE_H_INCLUDED
|
||||
#define WIDGETS_EDITOR_MOVING_PIXELS_STATE_H_INCLUDED
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "widgets/editor/standby_state.h"
|
||||
#include "widgets/statebar.h"
|
||||
|
||||
class Editor;
|
||||
class Image;
|
||||
class PixelsMovement;
|
||||
|
||||
class MovingPixelsState : public StandbyState, StatusBarListener
|
||||
{
|
||||
public:
|
||||
MovingPixelsState(Editor* editor, Message* msg, Image* imge, int x, int y, int opacity);
|
||||
virtual ~MovingPixelsState();
|
||||
|
||||
virtual void onBeforeChangeState(Editor* editor) OVERRIDE;
|
||||
virtual void onCurrentToolChange(Editor* editor) OVERRIDE;
|
||||
virtual bool onMouseDown(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseUp(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseMove(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseWheel(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onSetCursor(Editor* editor) OVERRIDE;
|
||||
virtual bool onKeyDown(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onKeyUp(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) OVERRIDE;
|
||||
|
||||
protected:
|
||||
// StatusBarListener interface
|
||||
virtual void dispose() OVERRIDE;
|
||||
virtual void onChangeTransparentColor(const Color& color) OVERRIDE;
|
||||
|
||||
private:
|
||||
void setTransparentColor(const Color& color);
|
||||
void dropPixels(Editor* editor);
|
||||
|
||||
// Helper member to move selection.
|
||||
PixelsMovement* m_pixelsMovement;
|
||||
};
|
||||
|
||||
#endif // WIDGETS_EDITOR_MOVING_PIXELS_STATE_H_INCLUDED
|
@ -179,6 +179,8 @@ public:
|
||||
DocumentWriter documentWriter(m_documentReader);
|
||||
m_undoTransaction.pasteImage(image, cel->getX(), cel->getY(), cel->getOpacity());
|
||||
m_undoTransaction.commit();
|
||||
|
||||
documentWriter->destroyExtraCel();
|
||||
}
|
||||
}
|
||||
|
||||
|
100
src/widgets/editor/scrolling_state.cpp
Normal file
100
src/widgets/editor/scrolling_state.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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 "widgets/editor/scrolling_state.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "gui/message.h"
|
||||
#include "gui/system.h"
|
||||
#include "gui/view.h"
|
||||
#include "modules/editors.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "widgets/editor/editor.h"
|
||||
#include "widgets/editor/standby_state.h"
|
||||
#include "widgets/statebar.h"
|
||||
|
||||
ScrollingState::ScrollingState()
|
||||
{
|
||||
}
|
||||
|
||||
ScrollingState::~ScrollingState()
|
||||
{
|
||||
}
|
||||
|
||||
bool ScrollingState::onMouseDown(Editor* editor, Message* msg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScrollingState::onMouseUp(Editor* editor, Message* msg)
|
||||
{
|
||||
editor->setState(new StandbyState);
|
||||
editor->releaseMouse();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScrollingState::onMouseMove(Editor* editor, Message* msg)
|
||||
{
|
||||
View* view = View::getView(editor);
|
||||
gfx::Rect vp = view->getViewportBounds();
|
||||
gfx::Point scroll = view->getViewScroll();
|
||||
|
||||
editor->setEditorScroll(scroll.x+jmouse_x(1)-jmouse_x(0),
|
||||
scroll.y+jmouse_y(1)-jmouse_y(0), true);
|
||||
|
||||
jmouse_control_infinite_scroll(vp);
|
||||
|
||||
int x, y;
|
||||
editor->screenToEditor(jmouse_x(0), jmouse_y(0), &x, &y);
|
||||
app_get_statusbar()->setStatusText
|
||||
(0, "Pos %3d %3d (Size %3d %3d)", x, y,
|
||||
editor->getSprite()->getWidth(),
|
||||
editor->getSprite()->getHeight());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScrollingState::onMouseWheel(Editor* editor, Message* msg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScrollingState::onSetCursor(Editor* editor)
|
||||
{
|
||||
editor->hideDrawingCursor();
|
||||
jmouse_set_cursor(JI_CURSOR_SCROLL);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScrollingState::onKeyDown(Editor* editor, Message* msg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScrollingState::onKeyUp(Editor* editor, Message* msg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScrollingState::onUpdateStatusBar(Editor* editor)
|
||||
{
|
||||
return false;
|
||||
}
|
40
src/widgets/editor/scrolling_state.h
Normal file
40
src/widgets/editor/scrolling_state.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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
|
||||
*/
|
||||
|
||||
#ifndef WIDGETS_EDITOR_SCROLLING_STATE_H_INCLUDED
|
||||
#define WIDGETS_EDITOR_SCROLLING_STATE_H_INCLUDED
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "widgets/editor/editor_state.h"
|
||||
|
||||
class ScrollingState : public EditorState
|
||||
{
|
||||
public:
|
||||
ScrollingState();
|
||||
virtual ~ScrollingState();
|
||||
virtual bool onMouseDown(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseUp(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseMove(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseWheel(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onSetCursor(Editor* editor) OVERRIDE;
|
||||
virtual bool onKeyDown(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onKeyUp(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) OVERRIDE;
|
||||
};
|
||||
|
||||
#endif // WIDGETS_EDITOR_SCROLLING_STATE_H_INCLUDED
|
383
src/widgets/editor/standby_state.cpp
Normal file
383
src/widgets/editor/standby_state.cpp
Normal file
@ -0,0 +1,383 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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 "widgets/editor/standby_state.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "commands/commands.h"
|
||||
#include "commands/params.h"
|
||||
#include "core/cfg.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "gui/alert.h"
|
||||
#include "gui/message.h"
|
||||
#include "gui/system.h"
|
||||
#include "gui/view.h"
|
||||
#include "modules/editors.h"
|
||||
#include "raster/layer.h"
|
||||
#include "raster/mask.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "tools/ink.h"
|
||||
#include "tools/tool.h"
|
||||
#include "ui_context.h"
|
||||
#include "util/misc.h"
|
||||
#include "widgets/color_bar.h"
|
||||
#include "widgets/editor/drawing_state.h"
|
||||
#include "widgets/editor/editor.h"
|
||||
#include "widgets/editor/moving_pixels_state.h"
|
||||
#include "widgets/editor/scrolling_state.h"
|
||||
#include "widgets/editor/tool_loop_impl.h"
|
||||
#include "widgets/statebar.h"
|
||||
|
||||
#include <allegro.h>
|
||||
|
||||
enum WHEEL_ACTION { WHEEL_NONE,
|
||||
WHEEL_ZOOM,
|
||||
WHEEL_VSCROLL,
|
||||
WHEEL_HSCROLL,
|
||||
WHEEL_FG,
|
||||
WHEEL_BG,
|
||||
WHEEL_FRAME };
|
||||
|
||||
static inline bool has_shifts(Message* msg, int shift)
|
||||
{
|
||||
return ((msg->any.shifts & shift) == shift);
|
||||
}
|
||||
|
||||
StandbyState::StandbyState()
|
||||
{
|
||||
}
|
||||
|
||||
StandbyState::~StandbyState()
|
||||
{
|
||||
}
|
||||
|
||||
bool StandbyState::onMouseDown(Editor* editor, Message* msg)
|
||||
{
|
||||
if (editor->hasCapture())
|
||||
return true;
|
||||
|
||||
UIContext* context = UIContext::instance();
|
||||
tools::Tool* current_tool = editor->getCurrentEditorTool();
|
||||
Sprite* sprite = editor->getSprite();
|
||||
|
||||
// Each time an editor is clicked the current editor and the active
|
||||
// document are set.
|
||||
set_current_editor(editor);
|
||||
context->setActiveDocument(editor->getDocument());
|
||||
|
||||
// Start scroll loop
|
||||
if (msg->mouse.middle ||
|
||||
current_tool->getInk(msg->mouse.right ? 1: 0)->isScrollMovement()) {
|
||||
editor->setState(new ScrollingState());
|
||||
editor->captureMouse();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Move frames position
|
||||
if (current_tool->getInk(msg->mouse.right ? 1: 0)->isCelMovement()) {
|
||||
if ((sprite->getCurrentLayer()) &&
|
||||
(sprite->getCurrentLayer()->getType() == GFXOBJ_LAYER_IMAGE)) {
|
||||
// TODO you can move the `Background' with tiled mode
|
||||
if (sprite->getCurrentLayer()->is_background()) {
|
||||
Alert::show(PACKAGE
|
||||
"<<You can't move the `Background' layer."
|
||||
"||&Close");
|
||||
}
|
||||
else if (!sprite->getCurrentLayer()->is_moveable()) {
|
||||
Alert::show(PACKAGE "<<The layer movement is locked.||&Close");
|
||||
}
|
||||
else {
|
||||
bool click2 = get_config_bool("Options", "MoveClick2", FALSE);
|
||||
|
||||
// TODO replace "interactive_move_layer" with a new EditorState
|
||||
interactive_move_layer(click2 ? Editor::MODE_CLICKANDCLICK:
|
||||
Editor::MODE_CLICKANDRELEASE,
|
||||
TRUE, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Move selected pixels
|
||||
else if (editor->isInsideSelection() &&
|
||||
current_tool->getInk(0)->isSelection() &&
|
||||
msg->mouse.left) {
|
||||
int x, y, opacity;
|
||||
Image* image = sprite->getCurrentImage(&x, &y, &opacity);
|
||||
if (image) {
|
||||
if (!sprite->getCurrentLayer()->is_writable()) {
|
||||
Alert::show(PACKAGE "<<The layer is locked.||&Close");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Change to MovingPixelsState
|
||||
editor->setState(new MovingPixelsState(editor, msg, image, x, y, opacity));
|
||||
}
|
||||
}
|
||||
// Call the eyedropper command
|
||||
else if (current_tool->getInk(msg->mouse.right ? 1: 0)->isEyedropper()) {
|
||||
Command* eyedropper_cmd =
|
||||
CommandsModule::instance()->getCommandByName(CommandId::Eyedropper);
|
||||
|
||||
Params params;
|
||||
params.set("target", msg->mouse.right ? "background": "foreground");
|
||||
|
||||
UIContext::instance()->executeCommand(eyedropper_cmd, ¶ms);
|
||||
return true;
|
||||
}
|
||||
// Start the Tool-Loop
|
||||
else if (sprite->getCurrentLayer()) {
|
||||
tools::ToolLoop* toolLoop = create_tool_loop(editor, context, msg);
|
||||
if (toolLoop)
|
||||
editor->setState(new DrawingState(toolLoop, editor, msg));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandbyState::onMouseUp(Editor* editor, Message* msg)
|
||||
{
|
||||
editor->releaseMouse();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandbyState::onMouseMove(Editor* editor, Message* msg)
|
||||
{
|
||||
editor->moveDrawingCursor();
|
||||
editor->updateStatusBar();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandbyState::onMouseWheel(Editor* editor, Message* msg)
|
||||
{
|
||||
int dz = jmouse_z(1) - jmouse_z(0);
|
||||
WHEEL_ACTION wheelAction = WHEEL_NONE;
|
||||
bool scrollBigSteps = false;
|
||||
|
||||
// Without modifiers
|
||||
if (!(msg->any.shifts & (KB_SHIFT_FLAG | KB_ALT_FLAG | KB_CTRL_FLAG))) {
|
||||
wheelAction = WHEEL_ZOOM;
|
||||
}
|
||||
else {
|
||||
#if 1 // TODO make it configurable
|
||||
if (has_shifts(msg, KB_ALT_FLAG)) {
|
||||
if (has_shifts(msg, KB_SHIFT_FLAG))
|
||||
wheelAction = WHEEL_BG;
|
||||
else
|
||||
wheelAction = WHEEL_FG;
|
||||
}
|
||||
else if (has_shifts(msg, KB_CTRL_FLAG)) {
|
||||
wheelAction = WHEEL_FRAME;
|
||||
}
|
||||
#else
|
||||
if (has_shifts(msg, KB_CTRL_FLAG))
|
||||
wheelAction = WHEEL_HSCROLL;
|
||||
else
|
||||
wheelAction = WHEEL_VSCROLL;
|
||||
|
||||
if (has_shifts(msg, KB_SHIFT_FLAG))
|
||||
scrollBigSteps = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (wheelAction) {
|
||||
|
||||
case WHEEL_NONE:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case WHEEL_FG:
|
||||
// if (m_state == EDITOR_STATE_STANDBY)
|
||||
{
|
||||
int newIndex = 0;
|
||||
if (app_get_colorbar()->getFgColor().getType() == Color::IndexType) {
|
||||
newIndex = app_get_colorbar()->getFgColor().getIndex() + dz;
|
||||
newIndex = MID(0, newIndex, 255);
|
||||
}
|
||||
app_get_colorbar()->setFgColor(Color::fromIndex(newIndex));
|
||||
}
|
||||
break;
|
||||
|
||||
case WHEEL_BG:
|
||||
// if (m_state == EDITOR_STATE_STANDBY)
|
||||
{
|
||||
int newIndex = 0;
|
||||
if (app_get_colorbar()->getBgColor().getType() == Color::IndexType) {
|
||||
newIndex = app_get_colorbar()->getBgColor().getIndex() + dz;
|
||||
newIndex = MID(0, newIndex, 255);
|
||||
}
|
||||
app_get_colorbar()->setBgColor(Color::fromIndex(newIndex));
|
||||
}
|
||||
break;
|
||||
|
||||
case WHEEL_FRAME:
|
||||
// if (m_state == EDITOR_STATE_STANDBY)
|
||||
{
|
||||
Command* command = CommandsModule::instance()->getCommandByName
|
||||
((dz < 0) ? CommandId::GotoNextFrame:
|
||||
CommandId::GotoPreviousFrame);
|
||||
if (command)
|
||||
UIContext::instance()->executeCommand(command, NULL);
|
||||
}
|
||||
break;
|
||||
|
||||
case WHEEL_ZOOM: {
|
||||
int zoom = MID(MIN_ZOOM, editor->getZoom()-dz, MAX_ZOOM);
|
||||
if (editor->getZoom() != zoom)
|
||||
editor->setZoomAndCenterInMouse(zoom, msg->mouse.x, msg->mouse.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case WHEEL_HSCROLL:
|
||||
case WHEEL_VSCROLL: {
|
||||
View* view = View::getView(editor);
|
||||
gfx::Rect vp = view->getViewportBounds();
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
|
||||
if (wheelAction == WHEEL_HSCROLL) {
|
||||
dx = dz * vp.w;
|
||||
}
|
||||
else {
|
||||
dy = dz * vp.h;
|
||||
}
|
||||
|
||||
if (scrollBigSteps) {
|
||||
dx /= 2;
|
||||
dy /= 2;
|
||||
}
|
||||
else {
|
||||
dx /= 10;
|
||||
dy /= 10;
|
||||
}
|
||||
|
||||
gfx::Point scroll = view->getViewScroll();
|
||||
|
||||
editor->hideDrawingCursor();
|
||||
editor->setEditorScroll(scroll.x+dx, scroll.y+dy, true);
|
||||
editor->showDrawingCursor();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandbyState::onSetCursor(Editor* editor)
|
||||
{
|
||||
tools::Tool* current_tool = editor->getCurrentEditorTool();
|
||||
|
||||
if (current_tool) {
|
||||
// If the current tool change selection (e.g. rectangular marquee, etc.)
|
||||
if (current_tool->getInk(0)->isSelection()) {
|
||||
// Move pixels
|
||||
if (editor->isInsideSelection()) {
|
||||
editor->hideDrawingCursor();
|
||||
|
||||
if (key[KEY_LCONTROL] ||
|
||||
key[KEY_RCONTROL]) // TODO configurable keys
|
||||
jmouse_set_cursor(JI_CURSOR_NORMAL_ADD);
|
||||
else
|
||||
jmouse_set_cursor(JI_CURSOR_MOVE);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (current_tool->getInk(0)->isEyedropper()) {
|
||||
editor->hideDrawingCursor();
|
||||
jmouse_set_cursor(JI_CURSOR_EYEDROPPER);
|
||||
return true;
|
||||
}
|
||||
else if (current_tool->getInk(0)->isScrollMovement()) {
|
||||
editor->hideDrawingCursor();
|
||||
jmouse_set_cursor(JI_CURSOR_SCROLL);
|
||||
return true;
|
||||
}
|
||||
else if (current_tool->getInk(0)->isCelMovement()) {
|
||||
editor->hideDrawingCursor();
|
||||
jmouse_set_cursor(JI_CURSOR_MOVE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw
|
||||
if (editor->canDraw()) {
|
||||
jmouse_set_cursor(JI_CURSOR_NULL);
|
||||
editor->showDrawingCursor();
|
||||
}
|
||||
// Forbidden
|
||||
else {
|
||||
editor->hideDrawingCursor();
|
||||
jmouse_set_cursor(JI_CURSOR_FORBIDDEN);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandbyState::onKeyDown(Editor* editor, Message* msg)
|
||||
{
|
||||
return editor->processKeysToSetZoom(msg->key.scancode);
|
||||
}
|
||||
|
||||
bool StandbyState::onKeyUp(Editor* editor, Message* msg)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StandbyState::onUpdateStatusBar(Editor* editor)
|
||||
{
|
||||
tools::Tool* current_tool = editor->getCurrentEditorTool();
|
||||
Sprite* sprite = editor->getSprite();
|
||||
int x, y;
|
||||
|
||||
editor->screenToEditor(jmouse_x(0), jmouse_y(0), &x, &y);
|
||||
|
||||
if (!sprite) {
|
||||
app_get_statusbar()->clearText();
|
||||
}
|
||||
// For eye-dropper
|
||||
else if (current_tool->getInk(0)->isEyedropper()) {
|
||||
int imgtype = sprite->getImgType();
|
||||
uint32_t pixel = sprite->getPixel(x, y);
|
||||
Color color = Color::fromImage(imgtype, pixel);
|
||||
|
||||
int alpha = 255;
|
||||
switch (imgtype) {
|
||||
case IMAGE_RGB: alpha = _rgba_geta(pixel); break;
|
||||
case IMAGE_GRAYSCALE: alpha = _graya_geta(pixel); break;
|
||||
}
|
||||
|
||||
char buf[256];
|
||||
usprintf(buf, "- Pos %d %d", x, y);
|
||||
|
||||
app_get_statusbar()->showColor(0, buf, color, alpha);
|
||||
}
|
||||
else {
|
||||
Mask* mask = editor->getDocument()->getMask();
|
||||
|
||||
app_get_statusbar()->setStatusText
|
||||
(0, "Pos %d %d, Size %d %d, Frame %d",
|
||||
x, y,
|
||||
((mask && mask->bitmap)? mask->w: sprite->getWidth()),
|
||||
((mask && mask->bitmap)? mask->h: sprite->getHeight()),
|
||||
sprite->getCurrentFrame()+1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
44
src/widgets/editor/standby_state.h
Normal file
44
src/widgets/editor/standby_state.h
Normal file
@ -0,0 +1,44 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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
|
||||
*/
|
||||
|
||||
#ifndef WIDGETS_EDITOR_STANDBY_STATE_H_INCLUDED
|
||||
#define WIDGETS_EDITOR_STANDBY_STATE_H_INCLUDED
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "widgets/editor/editor_state.h"
|
||||
|
||||
class StandbyState : public EditorState
|
||||
{
|
||||
public:
|
||||
StandbyState();
|
||||
virtual ~StandbyState();
|
||||
virtual bool onMouseDown(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseUp(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseMove(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onMouseWheel(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onSetCursor(Editor* editor) OVERRIDE;
|
||||
virtual bool onKeyDown(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onKeyUp(Editor* editor, Message* msg) OVERRIDE;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) OVERRIDE;
|
||||
|
||||
// Returns true as the standby state is the only one which shows the
|
||||
// pen-preview.
|
||||
virtual bool requirePenPreview() OVERRIDE { return true; }
|
||||
};
|
||||
|
||||
#endif // WIDGETS_EDITOR_STANDBY_STATE_H_INCLUDED
|
455
src/widgets/editor/tool_loop_impl.cpp
Normal file
455
src/widgets/editor/tool_loop_impl.cpp
Normal file
@ -0,0 +1,455 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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 "widgets/editor/tool_loop_impl.h"
|
||||
|
||||
#include "app.h"
|
||||
#include "app/color.h"
|
||||
#include "app/color_utils.h"
|
||||
#include "context.h"
|
||||
#include "gui/gui.h"
|
||||
#include "modules/editors.h"
|
||||
#include "raster/cel.h"
|
||||
#include "raster/dirty.h"
|
||||
#include "raster/image.h"
|
||||
#include "raster/layer.h"
|
||||
#include "raster/mask.h"
|
||||
#include "raster/pen.h"
|
||||
#include "raster/sprite.h"
|
||||
#include "raster/stock.h"
|
||||
#include "settings/settings.h"
|
||||
#include "tools/ink.h"
|
||||
#include "tools/tool.h"
|
||||
#include "tools/tool_loop.h"
|
||||
#include "undo/undo_history.h"
|
||||
#include "undoers/add_cel.h"
|
||||
#include "undoers/add_image.h"
|
||||
#include "undoers/close_group.h"
|
||||
#include "undoers/dirty_area.h"
|
||||
#include "undoers/open_group.h"
|
||||
#include "undoers/replace_image.h"
|
||||
#include "undoers/set_cel_position.h"
|
||||
#include "widgets/editor/editor.h"
|
||||
#include "widgets/color_bar.h"
|
||||
#include "widgets/statebar.h"
|
||||
|
||||
#include <allegro.h>
|
||||
|
||||
class ToolLoopImpl : public tools::ToolLoop
|
||||
{
|
||||
Editor* m_editor;
|
||||
Context* m_context;
|
||||
tools::Tool* m_tool;
|
||||
Pen* m_pen;
|
||||
Document* m_document;
|
||||
Sprite* m_sprite;
|
||||
Layer* m_layer;
|
||||
Cel* m_cel;
|
||||
Image* m_cel_image;
|
||||
bool m_cel_created;
|
||||
int m_old_cel_x;
|
||||
int m_old_cel_y;
|
||||
bool m_filled;
|
||||
bool m_previewFilled;
|
||||
int m_sprayWidth;
|
||||
int m_spraySpeed;
|
||||
TiledMode m_tiled_mode;
|
||||
Image* m_src_image;
|
||||
Image* m_dst_image;
|
||||
bool m_useMask;
|
||||
Mask* m_mask;
|
||||
gfx::Point m_maskOrigin;
|
||||
int m_opacity;
|
||||
int m_tolerance;
|
||||
gfx::Point m_offset;
|
||||
gfx::Point m_speed;
|
||||
bool m_canceled;
|
||||
int m_button;
|
||||
int m_primary_color;
|
||||
int m_secondary_color;
|
||||
|
||||
public:
|
||||
ToolLoopImpl(Editor* editor,
|
||||
Context* context,
|
||||
tools::Tool* tool,
|
||||
Document* document,
|
||||
Sprite* sprite,
|
||||
Layer* layer,
|
||||
int button, const Color& primary_color, const Color& secondary_color)
|
||||
: m_editor(editor)
|
||||
, m_context(context)
|
||||
, m_tool(tool)
|
||||
, m_document(document)
|
||||
, m_sprite(sprite)
|
||||
, m_layer(layer)
|
||||
, m_cel(NULL)
|
||||
, m_cel_image(NULL)
|
||||
, m_cel_created(false)
|
||||
, m_canceled(false)
|
||||
, m_button(button)
|
||||
, m_primary_color(color_utils::color_for_layer(primary_color, layer))
|
||||
, m_secondary_color(color_utils::color_for_layer(secondary_color, layer))
|
||||
{
|
||||
// Settings
|
||||
ISettings* settings = m_context->getSettings();
|
||||
|
||||
m_tiled_mode = settings->getTiledMode();
|
||||
|
||||
switch (tool->getFill(m_button)) {
|
||||
case tools::FillNone:
|
||||
m_filled = false;
|
||||
break;
|
||||
case tools::FillAlways:
|
||||
m_filled = true;
|
||||
break;
|
||||
case tools::FillOptional:
|
||||
m_filled = settings->getToolSettings(m_tool)->getFilled();
|
||||
break;
|
||||
}
|
||||
m_previewFilled = settings->getToolSettings(m_tool)->getPreviewFilled();
|
||||
|
||||
m_sprayWidth = settings->getToolSettings(m_tool)->getSprayWidth();
|
||||
m_spraySpeed = settings->getToolSettings(m_tool)->getSpraySpeed();
|
||||
|
||||
// Create the pen
|
||||
IPenSettings* pen_settings = settings->getToolSettings(m_tool)->getPen();
|
||||
ASSERT(pen_settings != NULL);
|
||||
|
||||
m_pen = new Pen(pen_settings->getType(),
|
||||
pen_settings->getSize(),
|
||||
pen_settings->getAngle());
|
||||
|
||||
// Get cel and image where we can draw
|
||||
|
||||
if (m_layer->is_image()) {
|
||||
m_cel = static_cast<LayerImage*>(sprite->getCurrentLayer())->getCel(sprite->getCurrentFrame());
|
||||
if (m_cel)
|
||||
m_cel_image = sprite->getStock()->getImage(m_cel->getImage());
|
||||
}
|
||||
|
||||
if (m_cel == NULL) {
|
||||
// create the image
|
||||
m_cel_image = image_new(sprite->getImgType(), sprite->getWidth(), sprite->getHeight());
|
||||
image_clear(m_cel_image,
|
||||
m_cel_image->mask_color);
|
||||
|
||||
// create the cel
|
||||
m_cel = new Cel(sprite->getCurrentFrame(), 0);
|
||||
static_cast<LayerImage*>(sprite->getCurrentLayer())->addCel(m_cel);
|
||||
|
||||
m_cel_created = true;
|
||||
}
|
||||
|
||||
m_old_cel_x = m_cel->getX();
|
||||
m_old_cel_y = m_cel->getY();
|
||||
|
||||
// region to draw
|
||||
int x1, y1, x2, y2;
|
||||
|
||||
// non-tiled
|
||||
if (m_tiled_mode == TILED_NONE) {
|
||||
x1 = MIN(m_cel->getX(), 0);
|
||||
y1 = MIN(m_cel->getY(), 0);
|
||||
x2 = MAX(m_cel->getX()+m_cel_image->w, m_sprite->getWidth());
|
||||
y2 = MAX(m_cel->getY()+m_cel_image->h, m_sprite->getHeight());
|
||||
}
|
||||
else { // tiled
|
||||
x1 = 0;
|
||||
y1 = 0;
|
||||
x2 = m_sprite->getWidth();
|
||||
y2 = m_sprite->getHeight();
|
||||
}
|
||||
|
||||
// create two copies of the image region which we'll modify with the tool
|
||||
m_src_image = image_crop(m_cel_image,
|
||||
x1-m_cel->getX(),
|
||||
y1-m_cel->getY(), x2-x1, y2-y1,
|
||||
m_cel_image->mask_color);
|
||||
m_dst_image = image_new_copy(m_src_image);
|
||||
|
||||
m_useMask = m_document->isMaskVisible();
|
||||
|
||||
// Selection ink
|
||||
if (getInk()->isSelection() && !m_document->isMaskVisible()) {
|
||||
Mask emptyMask;
|
||||
m_document->setMask(&emptyMask);
|
||||
}
|
||||
|
||||
m_mask = m_document->getMask();
|
||||
m_maskOrigin = (!m_mask->is_empty() ? gfx::Point(m_mask->x-x1, m_mask->y-y1):
|
||||
gfx::Point(0, 0));
|
||||
|
||||
m_opacity = settings->getToolSettings(m_tool)->getOpacity();
|
||||
m_tolerance = settings->getToolSettings(m_tool)->getTolerance();
|
||||
m_speed.x = 0;
|
||||
m_speed.y = 0;
|
||||
|
||||
// we have to modify the cel position because it's used in the
|
||||
// `render_sprite' routine to draw the `dst_image'
|
||||
m_cel->setPosition(x1, y1);
|
||||
m_offset.x = -x1;
|
||||
m_offset.y = -y1;
|
||||
|
||||
// Set undo label for any kind of undo used in the whole loop
|
||||
if (m_document->getUndoHistory()->isEnabled()) {
|
||||
m_document->getUndoHistory()->setLabel(m_tool->getText().c_str());
|
||||
|
||||
if (getInk()->isSelection() ||
|
||||
getInk()->isEyedropper() ||
|
||||
getInk()->isScrollMovement()) {
|
||||
m_document->getUndoHistory()->setModification(undo::DoesntModifyDocument);
|
||||
}
|
||||
else
|
||||
m_document->getUndoHistory()->setModification(undo::ModifyDocument);
|
||||
}
|
||||
}
|
||||
|
||||
~ToolLoopImpl()
|
||||
{
|
||||
if (!m_canceled) {
|
||||
undo::UndoHistory* undo = m_document->getUndoHistory();
|
||||
|
||||
// Paint ink
|
||||
if (getInk()->isPaint()) {
|
||||
// If the size of each image is the same, we can create an
|
||||
// undo with only the differences between both images.
|
||||
if (m_cel->getX() == m_old_cel_x &&
|
||||
m_cel->getY() == m_old_cel_y &&
|
||||
m_cel_image->w == m_dst_image->w &&
|
||||
m_cel_image->h == m_dst_image->h) {
|
||||
// Was the 'cel_image' created in the start of the tool-loop?.
|
||||
if (m_cel_created) {
|
||||
// Then we can keep the 'cel_image'...
|
||||
|
||||
// We copy the 'destination' image to the 'cel_image'.
|
||||
image_copy(m_cel_image, m_dst_image, 0, 0);
|
||||
|
||||
// Add the 'cel_image' in the images' stock of the sprite.
|
||||
m_cel->setImage(m_sprite->getStock()->addImage(m_cel_image));
|
||||
|
||||
// Is the undo enabled?.
|
||||
if (undo->isEnabled()) {
|
||||
// We can temporary remove the cel.
|
||||
static_cast<LayerImage*>(m_sprite->getCurrentLayer())->removeCel(m_cel);
|
||||
|
||||
// We create the undo information (for the new cel_image
|
||||
// in the stock and the new cel in the layer)...
|
||||
undo->pushUndoer(new undoers::OpenGroup());
|
||||
undo->pushUndoer(new undoers::AddImage(undo->getObjects(),
|
||||
m_sprite->getStock(), m_cel->getImage()));
|
||||
undo->pushUndoer(new undoers::AddCel(undo->getObjects(),
|
||||
m_sprite->getCurrentLayer(), m_cel));
|
||||
undo->pushUndoer(new undoers::CloseGroup());
|
||||
|
||||
// And finally we add the cel again in the layer.
|
||||
static_cast<LayerImage*>(m_sprite->getCurrentLayer())->addCel(m_cel);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Undo the dirty region.
|
||||
if (undo->isEnabled()) {
|
||||
Dirty* dirty = new Dirty(m_cel_image, m_dst_image);
|
||||
// TODO error handling
|
||||
|
||||
dirty->saveImagePixels(m_cel_image);
|
||||
if (dirty != NULL)
|
||||
undo->pushUndoer(new undoers::DirtyArea(undo->getObjects(),
|
||||
m_cel_image, dirty));
|
||||
|
||||
delete dirty;
|
||||
}
|
||||
|
||||
// Copy the 'dst_image' to the cel_image.
|
||||
image_copy(m_cel_image, m_dst_image, 0, 0);
|
||||
}
|
||||
}
|
||||
// If the size of both images are different, we have to
|
||||
// replace the entire image.
|
||||
else {
|
||||
if (undo->isEnabled()) {
|
||||
undo->pushUndoer(new undoers::OpenGroup());
|
||||
|
||||
if (m_cel->getX() != m_old_cel_x ||
|
||||
m_cel->getY() != m_old_cel_y) {
|
||||
int x = m_cel->getX();
|
||||
int y = m_cel->getY();
|
||||
m_cel->setPosition(m_old_cel_x, m_old_cel_y);
|
||||
|
||||
undo->pushUndoer(new undoers::SetCelPosition(undo->getObjects(), m_cel));
|
||||
|
||||
m_cel->setPosition(x, y);
|
||||
}
|
||||
|
||||
undo->pushUndoer(new undoers::ReplaceImage(undo->getObjects(),
|
||||
m_sprite->getStock(), m_cel->getImage()));
|
||||
undo->pushUndoer(new undoers::CloseGroup());
|
||||
}
|
||||
|
||||
// Replace the image in the stock.
|
||||
m_sprite->getStock()->replaceImage(m_cel->getImage(), m_dst_image);
|
||||
|
||||
// Destroy the old cel image.
|
||||
image_free(m_cel_image);
|
||||
|
||||
// Now the `dst_image' is used, so we haven't to destroy it.
|
||||
m_dst_image = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Selection ink
|
||||
if (getInk()->isSelection())
|
||||
m_document->generateMaskBoundaries();
|
||||
}
|
||||
|
||||
// If the trace was not canceled or it is not a 'paint' ink...
|
||||
if (m_canceled || !getInk()->isPaint()) {
|
||||
// Here we destroy the temporary 'cel' created and restore all as it was before
|
||||
|
||||
m_cel->setPosition(m_old_cel_x, m_old_cel_y);
|
||||
|
||||
if (m_cel_created) {
|
||||
static_cast<LayerImage*>(m_layer)->removeCel(m_cel);
|
||||
delete m_cel;
|
||||
delete m_cel_image;
|
||||
}
|
||||
}
|
||||
|
||||
delete m_src_image;
|
||||
delete m_dst_image;
|
||||
delete m_pen;
|
||||
}
|
||||
|
||||
// IToolLoop interface
|
||||
Context* getContext() { return m_context; }
|
||||
tools::Tool* getTool() { return m_tool; }
|
||||
Pen* getPen() { return m_pen; }
|
||||
Document* getDocument() { return m_document; }
|
||||
Sprite* getSprite() { return m_sprite; }
|
||||
Layer* getLayer() { return m_layer; }
|
||||
Image* getSrcImage() { return m_src_image; }
|
||||
Image* getDstImage() { return m_dst_image; }
|
||||
bool useMask() { return m_useMask; }
|
||||
Mask* getMask() { return m_mask; }
|
||||
gfx::Point getMaskOrigin() { return m_maskOrigin; }
|
||||
int getMouseButton() { return m_button; }
|
||||
int getPrimaryColor() { return m_primary_color; }
|
||||
void setPrimaryColor(int color) { m_primary_color = color; }
|
||||
int getSecondaryColor() { return m_secondary_color; }
|
||||
void setSecondaryColor(int color) { m_secondary_color = color; }
|
||||
int getOpacity() { return m_opacity; }
|
||||
int getTolerance() { return m_tolerance; }
|
||||
TiledMode getTiledMode() { return m_tiled_mode; }
|
||||
bool getFilled() { return m_filled; }
|
||||
bool getPreviewFilled() { return m_previewFilled; }
|
||||
int getSprayWidth() { return m_sprayWidth; }
|
||||
int getSpraySpeed() { return m_spraySpeed; }
|
||||
gfx::Point getOffset() { return m_offset; }
|
||||
void setSpeed(const gfx::Point& speed) { m_speed = speed; }
|
||||
gfx::Point getSpeed() { return m_speed; }
|
||||
tools::Ink* getInk() { return m_tool->getInk(m_button); }
|
||||
tools::Controller* getController() { return m_tool->getController(m_button); }
|
||||
tools::PointShape* getPointShape() { return m_tool->getPointShape(m_button); }
|
||||
tools::Intertwine* getIntertwine() { return m_tool->getIntertwine(m_button); }
|
||||
tools::TracePolicy getTracePolicy() { return m_tool->getTracePolicy(m_button); }
|
||||
|
||||
void cancel() { m_canceled = true; }
|
||||
bool isCanceled() { return m_canceled; }
|
||||
|
||||
gfx::Point screenToSprite(const gfx::Point& screenPoint)
|
||||
{
|
||||
gfx::Point spritePoint;
|
||||
m_editor->screenToEditor(screenPoint.x, screenPoint.y,
|
||||
&spritePoint.x, &spritePoint.y);
|
||||
return spritePoint;
|
||||
}
|
||||
|
||||
void updateArea(const gfx::Rect& dirty_area)
|
||||
{
|
||||
int x1 = dirty_area.x-m_offset.x;
|
||||
int y1 = dirty_area.y-m_offset.y;
|
||||
int x2 = dirty_area.x-m_offset.x+dirty_area.w-1;
|
||||
int y2 = dirty_area.y-m_offset.y+dirty_area.h-1;
|
||||
|
||||
acquire_bitmap(ji_screen);
|
||||
editors_draw_sprite_tiled(m_sprite, x1, y1, x2, y2);
|
||||
release_bitmap(ji_screen);
|
||||
}
|
||||
|
||||
void updateStatusBar(const char* text)
|
||||
{
|
||||
app_get_statusbar()->setStatusText(0, text);
|
||||
}
|
||||
};
|
||||
|
||||
tools::ToolLoop* create_tool_loop(Editor* editor, Context* context, Message* msg)
|
||||
{
|
||||
tools::Tool* current_tool = context->getSettings()->getCurrentTool();
|
||||
if (!current_tool)
|
||||
return NULL;
|
||||
|
||||
Sprite* sprite = editor->getSprite();
|
||||
Layer* layer = sprite->getCurrentLayer();
|
||||
|
||||
if (!layer) {
|
||||
Alert::show(PACKAGE "<<The current sprite does not have any layer.||&Close");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// If the active layer is not visible.
|
||||
if (!layer->is_readable()) {
|
||||
Alert::show(PACKAGE
|
||||
"<<The current layer is hidden,"
|
||||
"<<make it visible and try again"
|
||||
"||&Close");
|
||||
return NULL;
|
||||
}
|
||||
// If the active layer is read-only.
|
||||
else if (!layer->is_writable()) {
|
||||
Alert::show(PACKAGE
|
||||
"<<The current layer is locked,"
|
||||
"<<unlock it and try again"
|
||||
"||&Close");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Get fg/bg colors
|
||||
ColorBar* colorbar = app_get_colorbar();
|
||||
Color fg = colorbar->getFgColor();
|
||||
Color bg = colorbar->getBgColor();
|
||||
|
||||
if (!fg.isValid() || !bg.isValid()) {
|
||||
Alert::show(PACKAGE
|
||||
"<<The current selected foreground and/or background color"
|
||||
"<<is out of range. Select valid colors in the color-bar."
|
||||
"||&Close");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create the new tool loop
|
||||
return
|
||||
new ToolLoopImpl(editor,
|
||||
context,
|
||||
current_tool,
|
||||
editor->getDocument(),
|
||||
sprite, layer,
|
||||
msg->mouse.left ? 0: 1,
|
||||
msg->mouse.left ? fg: bg,
|
||||
msg->mouse.left ? bg: fg);
|
||||
}
|
32
src/widgets/editor/tool_loop_impl.h
Normal file
32
src/widgets/editor/tool_loop_impl.h
Normal file
@ -0,0 +1,32 @@
|
||||
/* ASE - Allegro Sprite Editor
|
||||
* Copyright (C) 2001-2011 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
|
||||
*/
|
||||
|
||||
#ifndef WIDGETS_EDITOR_TOOL_LOOP_IMPL_H_INCLUDED
|
||||
#define WIDGETS_EDITOR_TOOL_LOOP_IMPL_H_INCLUDED
|
||||
|
||||
namespace tools {
|
||||
class ToolLoop;
|
||||
}
|
||||
|
||||
class Context;
|
||||
class Editor;
|
||||
union Message;
|
||||
|
||||
tools::ToolLoop* create_tool_loop(Editor* editor, Context* context, Message* msg);
|
||||
|
||||
#endif
|
@ -164,6 +164,16 @@ StatusBar::~StatusBar()
|
||||
delete m_tipwindow; // widget
|
||||
}
|
||||
|
||||
void StatusBar::addListener(StatusBarListener* listener)
|
||||
{
|
||||
m_listeners.addListener(listener);
|
||||
}
|
||||
|
||||
void StatusBar::removeListener(StatusBarListener* listener)
|
||||
{
|
||||
m_listeners.removeListener(listener);
|
||||
}
|
||||
|
||||
void StatusBar::onCurrentToolChange()
|
||||
{
|
||||
if (isVisible()) {
|
||||
@ -177,8 +187,8 @@ void StatusBar::onCurrentToolChange()
|
||||
|
||||
void StatusBar::onTransparentColorChange()
|
||||
{
|
||||
if (current_editor)
|
||||
current_editor->setMaskColorForPixelsMovement(getTransparentColor());
|
||||
m_listeners.notify<const Color&>(&StatusBarListener::onChangeTransparentColor,
|
||||
getTransparentColor());
|
||||
}
|
||||
|
||||
void StatusBar::clearText()
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "base/compiler_specific.h"
|
||||
#include "gui/base.h"
|
||||
#include "gui/widget.h"
|
||||
#include "listeners.h"
|
||||
|
||||
class Box;
|
||||
class Button;
|
||||
@ -51,12 +52,25 @@ private:
|
||||
float m_pos;
|
||||
};
|
||||
|
||||
class StatusBarListener
|
||||
{
|
||||
public:
|
||||
virtual ~StatusBarListener() { }
|
||||
virtual void dispose() = 0;
|
||||
virtual void onChangeTransparentColor(const Color& color) = 0;
|
||||
};
|
||||
|
||||
typedef Listeners<StatusBarListener> StatusBarListeners;
|
||||
|
||||
class StatusBar : public Widget
|
||||
{
|
||||
public:
|
||||
StatusBar();
|
||||
~StatusBar();
|
||||
|
||||
void addListener(StatusBarListener* listener);
|
||||
void removeListener(StatusBarListener* listener);
|
||||
|
||||
void clearText();
|
||||
|
||||
bool setStatusText(int msecs, const char *format, ...);
|
||||
@ -116,6 +130,8 @@ private:
|
||||
Frame* m_tipwindow;
|
||||
|
||||
int m_hot_layer;
|
||||
|
||||
StatusBarListeners m_listeners;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user