mirror of
https://github.com/aseprite/aseprite.git
synced 2025-03-14 04:19:12 +00:00
Add BrushPreview class to wrap all code related to brush preview/editor cursor
This commit is contained in:
parent
ac82dcdd49
commit
f571e4ceb2
@ -311,7 +311,7 @@ add_library(app-lib
|
||||
ui/devconsole_view.cpp
|
||||
ui/document_view.cpp
|
||||
ui/drop_down_button.cpp
|
||||
ui/editor/cursor.cpp
|
||||
ui/editor/brush_preview.cpp
|
||||
ui/editor/drawing_state.cpp
|
||||
ui/editor/editor.cpp
|
||||
ui/editor/editor_observers.cpp
|
||||
|
@ -175,9 +175,6 @@ void App::initialize(const AppOptions& options)
|
||||
// Register well-known image file types.
|
||||
FileFormatsManager::instance()->registerAllFormats();
|
||||
|
||||
// init editor cursor
|
||||
Editor::initEditorCursor();
|
||||
|
||||
if (isPortable())
|
||||
PRINTF("Running in portable mode\n");
|
||||
|
||||
|
456
src/app/ui/editor/brush_preview.cpp
Normal file
456
src/app/ui/editor/brush_preview.cpp
Normal file
@ -0,0 +1,456 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/ui/editor/brush_preview.h"
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/color.h"
|
||||
#include "app/color_utils.h"
|
||||
#include "app/document.h"
|
||||
#include "app/tools/controller.h"
|
||||
#include "app/tools/ink.h"
|
||||
#include "app/tools/intertwine.h"
|
||||
#include "app/tools/point_shape.h"
|
||||
#include "app/tools/tool_loop.h"
|
||||
#include "app/ui/context_bar.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/editor/tool_loop_impl.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "doc/algo.h"
|
||||
#include "doc/blend_internals.h"
|
||||
#include "doc/brush.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/primitives.h"
|
||||
#include "doc/site.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace doc;
|
||||
|
||||
std::vector<gfx::Color> BrushPreview::m_savedPixels;
|
||||
int BrushPreview::m_savedPixelsIterator;
|
||||
|
||||
BrushPreview::BrushPreview(Editor* editor)
|
||||
: m_editor(editor)
|
||||
, m_type(CROSS)
|
||||
, m_onScreen(false)
|
||||
, m_screenPosition(0, 0)
|
||||
, m_editorPosition(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
BrushPreview::~BrushPreview()
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
Brush* BrushPreview::getCurrentBrush()
|
||||
{
|
||||
return App::instance()->getMainWindow()->getContextBar()->activeBrush().get();
|
||||
}
|
||||
|
||||
// static
|
||||
color_t BrushPreview::getBrushColor(Sprite* sprite, Layer* layer)
|
||||
{
|
||||
app::Color c = Preferences::instance().colorBar.fgColor();
|
||||
ASSERT(sprite != NULL);
|
||||
|
||||
// Avoid using invalid colors
|
||||
if (!c.isValid())
|
||||
return 0;
|
||||
|
||||
if (layer != NULL)
|
||||
return color_utils::color_for_layer(c, layer);
|
||||
else
|
||||
return color_utils::color_for_image(c, sprite->pixelFormat());
|
||||
}
|
||||
|
||||
// Draws the brush cursor in the specified absolute mouse position
|
||||
// given in 'pos' param. Warning: You should clean the cursor before
|
||||
// to use this routine with other editor.
|
||||
void BrushPreview::show(const gfx::Point& screenPos)
|
||||
{
|
||||
if (m_onScreen)
|
||||
hide();
|
||||
|
||||
app::Document* document = m_editor->document();
|
||||
Sprite* sprite = m_editor->sprite();
|
||||
Layer* layer = m_editor->layer();
|
||||
ASSERT(sprite);
|
||||
|
||||
// Get drawable region
|
||||
m_editor->getDrawableRegion(m_clippingRegion, ui::Widget::kCutTopWindows);
|
||||
|
||||
// Get cursor color
|
||||
app::Color app_cursor_color = Preferences::instance().editor.cursorColor();
|
||||
gfx::Color ui_cursor_color = color_utils::color_for_ui(app_cursor_color);
|
||||
m_blackAndWhiteNegative = (app_cursor_color.getType() == app::Color::MaskType);
|
||||
|
||||
// Cursor in the screen (view)
|
||||
m_screenPosition = screenPos;
|
||||
|
||||
// Get cursor position in the editor
|
||||
gfx::Point spritePos = m_editor->screenToEditor(screenPos);
|
||||
|
||||
// Get the current tool
|
||||
tools::Ink* ink = m_editor->getCurrentEditorInk();
|
||||
|
||||
// Setup the cursor type debrushding of several factors (current tool,
|
||||
// foreground color, and layer transparency).
|
||||
color_t brush_color = getBrushColor(sprite, layer);
|
||||
color_t mask_color = sprite->transparentColor();
|
||||
|
||||
if (ink->isSelection() || ink->isSlice()) {
|
||||
m_type = SELECTION_CROSS;
|
||||
}
|
||||
else if (
|
||||
// Use cursor bounds for inks that are effects (eraser, blur, etc.)
|
||||
(ink->isEffect()) ||
|
||||
// or when the brush color is transparent and we are not in the background layer
|
||||
(layer && !layer->isBackground() &&
|
||||
brush_color == mask_color)) {
|
||||
m_type = BRUSH_BOUNDARIES;
|
||||
}
|
||||
else {
|
||||
m_type = CROSS;
|
||||
}
|
||||
|
||||
// For cursor type 'bounds' we have to generate cursor boundaries
|
||||
if (m_type & BRUSH_BOUNDARIES)
|
||||
generateBoundaries();
|
||||
|
||||
// Draw pixel/brush preview
|
||||
if ((m_type & CROSS) && m_editor->getState()->requireBrushPreview()) {
|
||||
Brush* brush = getCurrentBrush();
|
||||
gfx::Rect brushBounds = brush->bounds();
|
||||
brushBounds.offset(spritePos);
|
||||
|
||||
// Create the extra cel to show the brush preview
|
||||
Site site = m_editor->getSite();
|
||||
Cel* cel = site.cel();
|
||||
|
||||
int t, opacity = 255;
|
||||
if (cel) opacity = MUL_UN8(opacity, cel->opacity(), t);
|
||||
if (layer) opacity = MUL_UN8(opacity, static_cast<LayerImage*>(layer)->opacity(), t);
|
||||
|
||||
document->prepareExtraCel(brushBounds, opacity);
|
||||
document->setExtraCelType(render::ExtraType::NONE);
|
||||
document->setExtraCelBlendMode(
|
||||
(layer ? static_cast<LayerImage*>(layer)->blendMode():
|
||||
BlendMode::NORMAL));
|
||||
|
||||
Image* extraImage = document->getExtraCelImage();
|
||||
extraImage->setMaskColor(mask_color);
|
||||
clear_image(extraImage, mask_color);
|
||||
|
||||
if (layer) {
|
||||
render::Render().renderLayer(
|
||||
extraImage, layer, m_editor->frame(),
|
||||
gfx::Clip(0, 0, brushBounds),
|
||||
BlendMode::SRC);
|
||||
|
||||
// This extra cel is a patch for the current layer/frame
|
||||
document->setExtraCelType(render::ExtraType::PATCH);
|
||||
}
|
||||
|
||||
tools::ToolLoop* loop = create_tool_loop_preview(
|
||||
m_editor, UIContext::instance(), extraImage,
|
||||
-gfx::Point(brushBounds.x,
|
||||
brushBounds.y));
|
||||
|
||||
if (loop) {
|
||||
loop->getInk()->prepareInk(loop);
|
||||
loop->getIntertwine()->prepareIntertwine();
|
||||
loop->getController()->prepareController();
|
||||
loop->getPointShape()->preparePointShape(loop);
|
||||
loop->getPointShape()->transformPoint(
|
||||
loop, -brush->bounds().x, -brush->bounds().y);
|
||||
delete loop;
|
||||
}
|
||||
|
||||
document->notifySpritePixelsModified(
|
||||
sprite, gfx::Region(m_lastBounds = brushBounds));
|
||||
}
|
||||
|
||||
// Save area and draw the cursor
|
||||
{
|
||||
ui::ScreenGraphics g;
|
||||
ui::SetClip clip(&g, gfx::Rect(0, 0, g.width(), g.height()));
|
||||
|
||||
forEachBrushPixel(&g, m_screenPosition, spritePos, ui_cursor_color, &BrushPreview::savePixelDelegate);
|
||||
forEachBrushPixel(&g, m_screenPosition, spritePos, ui_cursor_color, &BrushPreview::drawPixelDelegate);
|
||||
}
|
||||
|
||||
// Cursor in the editor (model)
|
||||
m_onScreen = true;
|
||||
m_editorPosition = spritePos;
|
||||
|
||||
// Save the clipping-region to know where to clean the pixels
|
||||
m_oldClippingRegion = m_clippingRegion;
|
||||
}
|
||||
|
||||
// Cleans the brush cursor from the specified editor.
|
||||
//
|
||||
// The mouse position is got from the last call to drawBrushPreview()
|
||||
// (m_cursorEditor). So you must to use this routine only if you
|
||||
// called drawBrushPreview() before.
|
||||
void BrushPreview::hide()
|
||||
{
|
||||
if (!m_onScreen)
|
||||
return;
|
||||
|
||||
app::Document* document = m_editor->document();
|
||||
Sprite* sprite = m_editor->sprite();
|
||||
ASSERT(sprite);
|
||||
|
||||
m_editor->getDrawableRegion(m_clippingRegion, ui::Widget::kCutTopWindows);
|
||||
|
||||
gfx::Point pos = m_editorPosition;
|
||||
|
||||
{
|
||||
// Restore pixels
|
||||
ui::ScreenGraphics g;
|
||||
ui::SetClip clip(&g, gfx::Rect(0, 0, g.width(), g.height()));
|
||||
|
||||
forEachBrushPixel(&g, m_screenPosition, pos, gfx::ColorNone,
|
||||
&BrushPreview::clearPixelDelegate);
|
||||
}
|
||||
|
||||
// Clean pixel/brush preview
|
||||
if ((m_type & CROSS) &&
|
||||
m_editor->getState()->requireBrushPreview()) {
|
||||
document->destroyExtraCel();
|
||||
document->notifySpritePixelsModified(
|
||||
sprite, gfx::Region(m_lastBounds));
|
||||
}
|
||||
|
||||
m_onScreen = false;
|
||||
m_clippingRegion.clear();
|
||||
m_oldClippingRegion.clear();
|
||||
}
|
||||
|
||||
void BrushPreview::redraw()
|
||||
{
|
||||
if (m_onScreen) {
|
||||
gfx::Point screenPos = m_screenPosition;
|
||||
hide();
|
||||
show(screenPos);
|
||||
}
|
||||
}
|
||||
|
||||
void BrushPreview::invalidateRegion(const gfx::Region& region)
|
||||
{
|
||||
m_clippingRegion.createSubtraction(m_clippingRegion, region);
|
||||
}
|
||||
|
||||
void BrushPreview::generateBoundaries()
|
||||
{
|
||||
Brush* brush = getCurrentBrush();
|
||||
|
||||
if (m_brushBoundaries &&
|
||||
m_brushGen == brush->gen())
|
||||
return;
|
||||
|
||||
Image* brushImage = brush->image();
|
||||
int w = brushImage->width();
|
||||
int h = brushImage->height();
|
||||
|
||||
m_brushGen = brush->gen();
|
||||
m_brushWidth = w;
|
||||
m_brushHeight = h;
|
||||
|
||||
ImageRef mask;
|
||||
if (brushImage->pixelFormat() != IMAGE_BITMAP) {
|
||||
mask.reset(Image::create(IMAGE_BITMAP, w, h));
|
||||
|
||||
LockImageBits<BitmapTraits> bits(mask.get());
|
||||
auto pos = bits.begin();
|
||||
for (int v=0; v<h; ++v) {
|
||||
for (int u=0; u<w; ++u) {
|
||||
*pos = get_pixel(brushImage, u, v);
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_brushBoundaries.reset(
|
||||
new MaskBoundaries(
|
||||
(mask ? mask.get(): brushImage)));
|
||||
}
|
||||
|
||||
void BrushPreview::forEachBrushPixel(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& screenPos,
|
||||
const gfx::Point& spritePos,
|
||||
gfx::Color color,
|
||||
PixelDelegate pixelDelegate)
|
||||
{
|
||||
m_savedPixelsIterator = 0;
|
||||
|
||||
if (m_type & CROSS)
|
||||
traceCrossPixels(g, screenPos, color, pixelDelegate);
|
||||
|
||||
if (m_type & SELECTION_CROSS)
|
||||
traceSelectionCrossPixels(g, spritePos, color, 1, pixelDelegate);
|
||||
|
||||
if (m_type & BRUSH_BOUNDARIES)
|
||||
traceBrushBoundaries(g, spritePos, color, pixelDelegate);
|
||||
|
||||
// Depending on the editor zoom, maybe wee need subpixel movement (a
|
||||
// little dot inside the active pixel)
|
||||
if (m_editor->zoom().scale() >= 4.0)
|
||||
(this->*pixelDelegate)(g, screenPos, color);
|
||||
}
|
||||
|
||||
void BrushPreview::traceCrossPixels(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& pt, gfx::Color color,
|
||||
PixelDelegate pixelDelegate)
|
||||
{
|
||||
static int cross[7*7] = {
|
||||
0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0,
|
||||
};
|
||||
gfx::Point out;
|
||||
int u, v;
|
||||
|
||||
for (v=0; v<7; v++) {
|
||||
for (u=0; u<7; u++) {
|
||||
if (cross[v*7+u]) {
|
||||
out.x = pt.x-3+u;
|
||||
out.y = pt.y-3+v;
|
||||
(this->*pixelDelegate)(g, out, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Old Thick Cross
|
||||
|
||||
void BrushPreview::traceSelectionCrossPixels(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& pt, gfx::Color color,
|
||||
int thickness, PixelDelegate pixelDelegate)
|
||||
{
|
||||
static int cross[6*6] = {
|
||||
0, 0, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 0, 0,
|
||||
1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1,
|
||||
0, 0, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 0, 0,
|
||||
};
|
||||
gfx::Point out, outpt = m_editor->editorToScreen(pt);
|
||||
int u, v;
|
||||
int size = m_editor->zoom().apply(thickness/2);
|
||||
int size2 = m_editor->zoom().apply(thickness);
|
||||
if (size2 == 0) size2 = 1;
|
||||
|
||||
for (v=0; v<6; v++) {
|
||||
for (u=0; u<6; u++) {
|
||||
if (!cross[v*6+u])
|
||||
continue;
|
||||
|
||||
out = outpt;
|
||||
out.x += ((u<3) ? u-size-3: u-size-3+size2);
|
||||
out.y += ((v<3) ? v-size-3: v-size-3+size2);
|
||||
|
||||
(this->*pixelDelegate)(g, out, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Current Brush Bounds
|
||||
|
||||
void BrushPreview::traceBrushBoundaries(ui::Graphics* g,
|
||||
gfx::Point pos,
|
||||
gfx::Color color,
|
||||
PixelDelegate pixelDelegate)
|
||||
{
|
||||
pos.x -= m_brushWidth/2;
|
||||
pos.y -= m_brushHeight/2;
|
||||
|
||||
for (const auto& seg : *m_brushBoundaries) {
|
||||
gfx::Rect bounds = seg.bounds();
|
||||
bounds.offset(pos);
|
||||
bounds = m_editor->editorToScreen(bounds);
|
||||
|
||||
if (seg.open()) {
|
||||
if (seg.vertical()) --bounds.x;
|
||||
else --bounds.y;
|
||||
}
|
||||
|
||||
gfx::Point pt(bounds.x, bounds.y);
|
||||
if (seg.vertical()) {
|
||||
for (; pt.y<bounds.y+bounds.h; ++pt.y)
|
||||
(this->*pixelDelegate)(g, pt, color);
|
||||
}
|
||||
else {
|
||||
for (; pt.x<bounds.x+bounds.w; ++pt.x)
|
||||
(this->*pixelDelegate)(g, pt, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BrushPreview::savePixelDelegate(ui::Graphics* g, const gfx::Point& pt, gfx::Color color)
|
||||
{
|
||||
if (m_clippingRegion.contains(pt)) {
|
||||
color_t c = g->getPixel(pt.x, pt.y);
|
||||
|
||||
if (m_savedPixelsIterator < (int)m_savedPixels.size())
|
||||
m_savedPixels[m_savedPixelsIterator] = c;
|
||||
else
|
||||
m_savedPixels.push_back(c);
|
||||
|
||||
++m_savedPixelsIterator;
|
||||
}
|
||||
}
|
||||
|
||||
void BrushPreview::drawPixelDelegate(ui::Graphics* gfx, const gfx::Point& pt, gfx::Color color)
|
||||
{
|
||||
if (m_savedPixelsIterator < (int)m_savedPixels.size() &&
|
||||
m_clippingRegion.contains(pt)) {
|
||||
if (m_blackAndWhiteNegative) {
|
||||
int c = m_savedPixels[m_savedPixelsIterator++];
|
||||
int r = gfx::getr(c);
|
||||
int g = gfx::getg(c);
|
||||
int b = gfx::getb(c);
|
||||
|
||||
gfx->putPixel(color_utils::blackandwhite_neg(gfx::rgba(r, g, b)), pt.x, pt.y);
|
||||
}
|
||||
else {
|
||||
gfx->putPixel(color, pt.x, pt.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BrushPreview::clearPixelDelegate(ui::Graphics* g, const gfx::Point& pt, gfx::Color color)
|
||||
{
|
||||
if (m_savedPixelsIterator < (int)m_savedPixels.size()) {
|
||||
if (m_clippingRegion.contains(pt))
|
||||
g->putPixel(m_savedPixels[m_savedPixelsIterator++], pt.x, pt.y);
|
||||
else if (!m_oldClippingRegion.isEmpty() &&
|
||||
m_oldClippingRegion.contains(pt))
|
||||
m_savedPixelsIterator++;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace app
|
129
src/app/ui/editor/brush_preview.h
Normal file
129
src/app/ui/editor/brush_preview.h
Normal file
@ -0,0 +1,129 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_UI_EDITOR_BRUSH_PREVIEW_H_INCLUDED
|
||||
#define APP_UI_EDITOR_BRUSH_PREVIEW_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
#include "base/shared_ptr.h"
|
||||
#include "doc/color.h"
|
||||
#include "doc/mask_boundaries.h"
|
||||
#include "gfx/color.h"
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "gfx/region.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace doc {
|
||||
class Brush;
|
||||
class Layer;
|
||||
class Sprite;
|
||||
}
|
||||
|
||||
namespace ui {
|
||||
class Graphics;
|
||||
}
|
||||
|
||||
namespace app {
|
||||
class Editor;
|
||||
|
||||
class BrushPreview {
|
||||
public:
|
||||
// Brush type
|
||||
enum {
|
||||
CROSS = 1,
|
||||
SELECTION_CROSS = 2,
|
||||
BRUSH_BOUNDARIES = 4,
|
||||
};
|
||||
|
||||
BrushPreview(Editor* editor);
|
||||
~BrushPreview();
|
||||
|
||||
bool onScreen() const { return m_onScreen; }
|
||||
const gfx::Point& screenPosition() const { return m_screenPosition; }
|
||||
|
||||
void show(const gfx::Point& screenPos);
|
||||
void move(const gfx::Point& screenPos);
|
||||
void hide();
|
||||
void redraw();
|
||||
|
||||
void invalidateRegion(const gfx::Region& region);
|
||||
|
||||
private:
|
||||
typedef void (BrushPreview::*PixelDelegate)(ui::Graphics*, const gfx::Point&, gfx::Color);
|
||||
|
||||
static doc::Brush* getCurrentBrush();
|
||||
static doc::color_t getBrushColor(doc::Sprite* sprite, doc::Layer* layer);
|
||||
|
||||
void generateBoundaries();
|
||||
void forEachBrushPixel(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& screenPos,
|
||||
const gfx::Point& spritePos,
|
||||
gfx::Color color,
|
||||
PixelDelegate pixelDelegate);
|
||||
|
||||
void traceCrossPixels(ui::Graphics* g, const gfx::Point& pt, gfx::Color color, PixelDelegate pixel);
|
||||
void traceSelectionCrossPixels(ui::Graphics* g, const gfx::Point& pt, gfx::Color color, int thickness, PixelDelegate pixel);
|
||||
void traceBrushBoundaries(ui::Graphics* g, gfx::Point pos, gfx::Color color, PixelDelegate pixel);
|
||||
|
||||
void savePixelDelegate(ui::Graphics* g, const gfx::Point& pt, gfx::Color color);
|
||||
void drawPixelDelegate(ui::Graphics* g, const gfx::Point& pt, gfx::Color color);
|
||||
void clearPixelDelegate(ui::Graphics* g, const gfx::Point& pt, gfx::Color color);
|
||||
|
||||
Editor* m_editor;
|
||||
int m_type;
|
||||
|
||||
// The brush preview shows the cross or brush boundaries as black
|
||||
// & white negative.
|
||||
bool m_blackAndWhiteNegative;
|
||||
|
||||
// The brush preview is on the screen.
|
||||
bool m_onScreen;
|
||||
gfx::Point m_screenPosition; // Position in the screen (view)
|
||||
gfx::Point m_editorPosition; // Position in the editor (model)
|
||||
|
||||
// Information about current brush
|
||||
base::SharedPtr<doc::MaskBoundaries> m_brushBoundaries;
|
||||
int m_brushGen;
|
||||
int m_brushWidth;
|
||||
int m_brushHeight;
|
||||
|
||||
static std::vector<gfx::Color> m_savedPixels;
|
||||
static int m_savedPixelsIterator;
|
||||
|
||||
gfx::Region m_clippingRegion;
|
||||
gfx::Region m_oldClippingRegion;
|
||||
|
||||
gfx::Rect m_lastBounds;
|
||||
};
|
||||
|
||||
class HideBrushPreview {
|
||||
public:
|
||||
HideBrushPreview(BrushPreview& brushPreview)
|
||||
: m_brushPreview(brushPreview)
|
||||
, m_oldScreenPosition(brushPreview.screenPosition())
|
||||
, m_onScreen(brushPreview.onScreen()) {
|
||||
if (m_onScreen)
|
||||
m_brushPreview.hide();
|
||||
}
|
||||
|
||||
~HideBrushPreview() {
|
||||
if (m_onScreen)
|
||||
m_brushPreview.show(m_oldScreenPosition);
|
||||
}
|
||||
|
||||
private:
|
||||
BrushPreview& m_brushPreview;
|
||||
gfx::Point m_oldScreenPosition;
|
||||
bool m_onScreen;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -1,513 +0,0 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "app/ui/editor/editor.h"
|
||||
|
||||
#include "app/app.h"
|
||||
#include "app/color.h"
|
||||
#include "app/color_utils.h"
|
||||
#include "app/ini_file.h"
|
||||
#include "app/modules/editors.h"
|
||||
#include "app/tools/controller.h"
|
||||
#include "app/tools/ink.h"
|
||||
#include "app/tools/intertwine.h"
|
||||
#include "app/tools/point_shape.h"
|
||||
#include "app/tools/tool.h"
|
||||
#include "app/tools/tool_loop.h"
|
||||
#include "app/ui/context_bar.h"
|
||||
#include "app/ui/editor/tool_loop_impl.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "base/bind.h"
|
||||
#include "base/memory.h"
|
||||
#include "doc/algo.h"
|
||||
#include "doc/blend_internals.h"
|
||||
#include "doc/brush.h"
|
||||
#include "doc/cel.h"
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/mask_boundaries.h"
|
||||
#include "doc/primitives.h"
|
||||
#include "doc/site.h"
|
||||
#include "doc/sprite.h"
|
||||
#include "render/render.h"
|
||||
#include "ui/base.h"
|
||||
#include "ui/system.h"
|
||||
#include "ui/widget.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace app {
|
||||
|
||||
using namespace ui;
|
||||
|
||||
// Returns true if the cursor of the editor needs subpixel movement.
|
||||
#define IS_SUBPIXEL(editor) ((editor)->m_zoom.scale() >= 4.0)
|
||||
|
||||
static struct {
|
||||
MaskBoundaries* boundaries;
|
||||
int brush_gen;
|
||||
int brush_width;
|
||||
int brush_height;
|
||||
} cursor_bound = { nullptr, 0, 0, 0 };
|
||||
|
||||
enum {
|
||||
CURSOR_THINCROSS = 1,
|
||||
CURSOR_THICKCROSS = 2,
|
||||
CURSOR_BRUSHBOUNDS = 4
|
||||
};
|
||||
|
||||
static int cursor_type = CURSOR_THINCROSS;
|
||||
static bool cursor_negative;
|
||||
|
||||
static std::vector<gfx::Color> saved_pixel;
|
||||
static int saved_pixel_n;
|
||||
|
||||
// These clipping regions are shared between all editors, so we cannot
|
||||
// make assumptions about their old state
|
||||
static gfx::Region clipping_region;
|
||||
static gfx::Region old_clipping_region;
|
||||
|
||||
static gfx::Rect lastBrushBounds;
|
||||
|
||||
static void generate_cursor_boundaries();
|
||||
|
||||
static void trace_thincross_pixels(ui::Graphics* g, Editor* editor, const gfx::Point& pt, gfx::Color color, Editor::PixelDelegate pixel);
|
||||
static void trace_thickcross_pixels(ui::Graphics* g, Editor* editor, const gfx::Point& pt, gfx::Color color, int thickness, Editor::PixelDelegate pixel);
|
||||
static void trace_brush_bounds(ui::Graphics* g, Editor* editor, gfx::Point pos, gfx::Color color, Editor::PixelDelegate pixel);
|
||||
|
||||
static void savepixel(ui::Graphics* g, const gfx::Point& pt, gfx::Color color);
|
||||
static void drawpixel(ui::Graphics* g, const gfx::Point& pt, gfx::Color color);
|
||||
static void clearpixel(ui::Graphics* g, const gfx::Point& pt, gfx::Color color);
|
||||
|
||||
static color_t get_brush_color(Sprite* sprite, Layer* layer);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// CURSOR COLOR
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
static gfx::Color ui_cursor_color;
|
||||
static bool is_cursor_mask;
|
||||
|
||||
static void update_cursor_color()
|
||||
{
|
||||
app::Color color = Preferences::instance().editor.cursorColor();
|
||||
|
||||
ui_cursor_color = color_utils::color_for_ui(color);
|
||||
is_cursor_mask = (color.getType() == app::Color::MaskType);
|
||||
}
|
||||
|
||||
static Brush* get_current_brush()
|
||||
{
|
||||
return App::instance()->getMainWindow()->getContextBar()->activeBrush().get();
|
||||
}
|
||||
|
||||
void Editor::initEditorCursor()
|
||||
{
|
||||
update_cursor_color();
|
||||
|
||||
Preferences::instance().editor.cursorColor.AfterChange.connect(
|
||||
Bind<void>(&update_cursor_color));
|
||||
|
||||
App::instance()->PaletteChange.connect(&update_cursor_color);
|
||||
}
|
||||
|
||||
void Editor::exitEditorCursor()
|
||||
{
|
||||
delete cursor_bound.boundaries;
|
||||
cursor_bound.boundaries = nullptr;
|
||||
}
|
||||
|
||||
// Draws the brush cursor in the specified absolute mouse position
|
||||
// given in 'pos' param. Warning: You should clean the cursor before
|
||||
// to use this routine with other editor.
|
||||
void Editor::drawBrushPreview(const gfx::Point& pos)
|
||||
{
|
||||
ASSERT(!m_cursorOnScreen);
|
||||
ASSERT(m_sprite);
|
||||
|
||||
// Get drawable region
|
||||
getDrawableRegion(clipping_region, kCutTopWindows);
|
||||
|
||||
// Get cursor color
|
||||
cursor_negative = is_cursor_mask;
|
||||
|
||||
// Cursor in the screen (view)
|
||||
m_cursorScreen = pos;
|
||||
|
||||
// Get cursor position in the editor
|
||||
gfx::Point spritePos = screenToEditor(pos);
|
||||
|
||||
// Get the current tool
|
||||
tools::Ink* ink = getCurrentEditorInk();
|
||||
|
||||
// Setup the cursor type debrushding of several factors (current tool,
|
||||
// foreground color, and layer transparency).
|
||||
color_t brush_color = get_brush_color(m_sprite, m_layer);
|
||||
color_t mask_color = m_sprite->transparentColor();
|
||||
|
||||
if (ink->isSelection() || ink->isSlice()) {
|
||||
cursor_type = CURSOR_THICKCROSS;
|
||||
}
|
||||
else if (
|
||||
// Use cursor bounds for inks that are effects (eraser, blur, etc.)
|
||||
(ink->isEffect()) ||
|
||||
// or when the brush color is transparent and we are not in the background layer
|
||||
(m_layer && !m_layer->isBackground() &&
|
||||
brush_color == mask_color)) {
|
||||
cursor_type = CURSOR_BRUSHBOUNDS;
|
||||
}
|
||||
else {
|
||||
cursor_type = CURSOR_THINCROSS;
|
||||
}
|
||||
|
||||
// For cursor type 'bounds' we have to generate cursor boundaries
|
||||
if (cursor_type & CURSOR_BRUSHBOUNDS)
|
||||
generate_cursor_boundaries();
|
||||
|
||||
// Draw pixel/brush preview
|
||||
if (cursor_type & CURSOR_THINCROSS && m_state->requireBrushPreview()) {
|
||||
Brush* brush = get_current_brush();
|
||||
gfx::Rect brushBounds = brush->bounds();
|
||||
brushBounds.offset(spritePos);
|
||||
|
||||
// Create the extra cel to show the brush preview
|
||||
Site site = getSite();
|
||||
Cel* cel = site.cel();
|
||||
|
||||
int t, opacity = 255;
|
||||
if (cel) opacity = MUL_UN8(opacity, cel->opacity(), t);
|
||||
if (m_layer) opacity = MUL_UN8(opacity, static_cast<LayerImage*>(m_layer)->opacity(), t);
|
||||
|
||||
m_document->prepareExtraCel(brushBounds, opacity);
|
||||
m_document->setExtraCelType(render::ExtraType::NONE);
|
||||
m_document->setExtraCelBlendMode(
|
||||
(m_layer ? static_cast<LayerImage*>(m_layer)->blendMode():
|
||||
BlendMode::NORMAL));
|
||||
|
||||
Image* extraImage = m_document->getExtraCelImage();
|
||||
extraImage->setMaskColor(mask_color);
|
||||
clear_image(extraImage, mask_color);
|
||||
|
||||
if (m_layer) {
|
||||
render::Render().renderLayer(
|
||||
extraImage, m_layer, m_frame,
|
||||
gfx::Clip(0, 0, brushBounds),
|
||||
BlendMode::SRC);
|
||||
|
||||
// This extra cel is a patch for the current layer/frame
|
||||
m_document->setExtraCelType(render::ExtraType::PATCH);
|
||||
}
|
||||
|
||||
tools::ToolLoop* loop = create_tool_loop_preview(
|
||||
this, UIContext::instance(), extraImage,
|
||||
-gfx::Point(brushBounds.x,
|
||||
brushBounds.y));
|
||||
|
||||
if (loop) {
|
||||
loop->getInk()->prepareInk(loop);
|
||||
loop->getIntertwine()->prepareIntertwine();
|
||||
loop->getController()->prepareController();
|
||||
loop->getPointShape()->preparePointShape(loop);
|
||||
loop->getPointShape()->transformPoint(
|
||||
loop, -brush->bounds().x, -brush->bounds().y);
|
||||
delete loop;
|
||||
}
|
||||
|
||||
m_document->notifySpritePixelsModified(
|
||||
m_sprite,
|
||||
gfx::Region(lastBrushBounds = brushBounds));
|
||||
}
|
||||
|
||||
// Save area and draw the cursor
|
||||
{
|
||||
ScreenGraphics g;
|
||||
SetClip clip(&g, gfx::Rect(0, 0, g.width(), g.height()));
|
||||
|
||||
forEachBrushPixel(&g, m_cursorScreen, spritePos, ui_cursor_color, savepixel);
|
||||
forEachBrushPixel(&g, m_cursorScreen, spritePos, ui_cursor_color, drawpixel);
|
||||
}
|
||||
|
||||
// Cursor in the editor (model)
|
||||
m_cursorOnScreen = true;
|
||||
m_cursorEditor = spritePos;
|
||||
|
||||
// Save the clipping-region to know where to clean the pixels
|
||||
old_clipping_region = clipping_region;
|
||||
}
|
||||
|
||||
// Cleans the brush cursor from the specified editor.
|
||||
//
|
||||
// The mouse position is got from the last call to drawBrushPreview()
|
||||
// (m_cursorEditor). So you must to use this routine only if you
|
||||
// called drawBrushPreview() before.
|
||||
void Editor::clearBrushPreview()
|
||||
{
|
||||
ASSERT(m_cursorOnScreen);
|
||||
ASSERT(m_sprite);
|
||||
|
||||
getDrawableRegion(clipping_region, kCutTopWindows);
|
||||
|
||||
gfx::Point pos = m_cursorEditor;
|
||||
|
||||
{
|
||||
// Restore pixels
|
||||
ScreenGraphics g;
|
||||
SetClip clip(&g, gfx::Rect(0, 0, g.width(), g.height()));
|
||||
|
||||
forEachBrushPixel(&g, m_cursorScreen, pos, gfx::ColorNone, clearpixel);
|
||||
}
|
||||
|
||||
// Clean pixel/brush preview
|
||||
if (cursor_type & CURSOR_THINCROSS && m_state->requireBrushPreview()) {
|
||||
m_document->destroyExtraCel();
|
||||
m_document->notifySpritePixelsModified(
|
||||
m_sprite, gfx::Region(lastBrushBounds));
|
||||
}
|
||||
|
||||
m_cursorOnScreen = false;
|
||||
|
||||
clipping_region.clear();
|
||||
old_clipping_region.clear();
|
||||
}
|
||||
|
||||
// Returns true if the cursor to draw in the editor has subpixel
|
||||
// movement (a little pixel of the screen that indicates where is the
|
||||
// mouse inside the pixel of the sprite).
|
||||
bool Editor::doesBrushPreviewNeedSubpixel()
|
||||
{
|
||||
return IS_SUBPIXEL(this);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void generate_cursor_boundaries()
|
||||
{
|
||||
Brush* brush = get_current_brush();
|
||||
|
||||
if (cursor_bound.boundaries &&
|
||||
cursor_bound.brush_gen == brush->gen())
|
||||
return;
|
||||
|
||||
Image* brush_image = brush->image();
|
||||
int w = brush_image->width();
|
||||
int h = brush_image->height();
|
||||
|
||||
cursor_bound.brush_gen = brush->gen();
|
||||
cursor_bound.brush_width = w;
|
||||
cursor_bound.brush_height = h;
|
||||
|
||||
ImageRef mask;
|
||||
if (brush_image->pixelFormat() != IMAGE_BITMAP) {
|
||||
mask.reset(Image::create(IMAGE_BITMAP, w, h));
|
||||
|
||||
LockImageBits<BitmapTraits> bits(mask.get());
|
||||
auto pos = bits.begin();
|
||||
for (int v=0; v<h; ++v) {
|
||||
for (int u=0; u<w; ++u) {
|
||||
*pos = get_pixel(brush_image, u, v);
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete cursor_bound.boundaries;
|
||||
cursor_bound.boundaries = new MaskBoundaries(
|
||||
(mask ? mask.get(): brush_image));
|
||||
}
|
||||
|
||||
void Editor::forEachBrushPixel(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& screenPos,
|
||||
const gfx::Point& spritePos,
|
||||
gfx::Color color,
|
||||
Editor::PixelDelegate pixelDelegate)
|
||||
{
|
||||
saved_pixel_n = 0;
|
||||
|
||||
if (cursor_type & CURSOR_THINCROSS)
|
||||
trace_thincross_pixels(g, this, screenPos, color, pixelDelegate);
|
||||
|
||||
if (cursor_type & CURSOR_THICKCROSS)
|
||||
trace_thickcross_pixels(g, this, spritePos, color, 1, pixelDelegate);
|
||||
|
||||
if (cursor_type & CURSOR_BRUSHBOUNDS)
|
||||
trace_brush_bounds(g, this, spritePos, color, pixelDelegate);
|
||||
|
||||
if (IS_SUBPIXEL(this)) {
|
||||
pixelDelegate(g, screenPos, color);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// New Thin Cross
|
||||
|
||||
static void trace_thincross_pixels(ui::Graphics* g, Editor* editor,
|
||||
const gfx::Point& pt, gfx::Color color, Editor::PixelDelegate pixelDelegate)
|
||||
{
|
||||
static int cursor_cross[7*7] = {
|
||||
0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 0, 0,
|
||||
};
|
||||
gfx::Point out;
|
||||
int u, v;
|
||||
|
||||
for (v=0; v<7; v++) {
|
||||
for (u=0; u<7; u++) {
|
||||
if (cursor_cross[v*7+u]) {
|
||||
out.x = pt.x-3+u;
|
||||
out.y = pt.y-3+v;
|
||||
pixelDelegate(g, out, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Old Thick Cross
|
||||
|
||||
static void trace_thickcross_pixels(ui::Graphics* g, Editor* editor,
|
||||
const gfx::Point& pt, gfx::Color color, int thickness, Editor::PixelDelegate pixelDelegate)
|
||||
{
|
||||
static int cursor_cross[6*6] = {
|
||||
0, 0, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 0, 0,
|
||||
1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1,
|
||||
0, 0, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 0, 0,
|
||||
};
|
||||
gfx::Point out, outpt = editor->editorToScreen(pt);
|
||||
int u, v;
|
||||
int size = editor->zoom().apply(thickness/2);
|
||||
int size2 = editor->zoom().apply(thickness);
|
||||
if (size2 == 0) size2 = 1;
|
||||
|
||||
for (v=0; v<6; v++) {
|
||||
for (u=0; u<6; u++) {
|
||||
if (!cursor_cross[v*6+u])
|
||||
continue;
|
||||
|
||||
out = outpt;
|
||||
out.x += ((u<3) ? u-size-3: u-size-3+size2);
|
||||
out.y += ((v<3) ? v-size-3: v-size-3+size2);
|
||||
|
||||
pixelDelegate(g, out, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Current Brush Bounds
|
||||
|
||||
struct Data {
|
||||
ui::Graphics* g;
|
||||
gfx::Color color;
|
||||
Editor::PixelDelegate pixelDelegate;
|
||||
};
|
||||
|
||||
static void algo_line_proxy(int x, int y, void* _data)
|
||||
{
|
||||
Data* data = (Data*)_data;
|
||||
data->pixelDelegate(data->g, gfx::Point(x, y), data->color);
|
||||
}
|
||||
|
||||
static void trace_brush_bounds(ui::Graphics* g, Editor* editor,
|
||||
gfx::Point pos, gfx::Color color, Editor::PixelDelegate pixelDelegate)
|
||||
{
|
||||
Data data = { g, color, pixelDelegate };
|
||||
|
||||
pos.x -= cursor_bound.brush_width/2;
|
||||
pos.y -= cursor_bound.brush_height/2;
|
||||
|
||||
for (const auto& seg : *cursor_bound.boundaries) {
|
||||
gfx::Rect bounds = seg.bounds();
|
||||
bounds.offset(pos);
|
||||
bounds = editor->editorToScreen(bounds);
|
||||
|
||||
if (seg.open()) {
|
||||
if (seg.vertical()) --bounds.x;
|
||||
else --bounds.y;
|
||||
}
|
||||
|
||||
if (seg.vertical())
|
||||
doc::algo_line(bounds.x, bounds.y, bounds.x, bounds.y+bounds.h-1, (void*)&data, algo_line_proxy);
|
||||
else
|
||||
doc::algo_line(bounds.x, bounds.y, bounds.x+bounds.w-1, bounds.y, (void*)&data, algo_line_proxy);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Helpers
|
||||
|
||||
static void savepixel(ui::Graphics* g, const gfx::Point& pt, gfx::Color color)
|
||||
{
|
||||
if (clipping_region.contains(pt)) {
|
||||
color_t c = g->getPixel(pt.x, pt.y);
|
||||
|
||||
if (saved_pixel_n < (int)saved_pixel.size())
|
||||
saved_pixel[saved_pixel_n] = c;
|
||||
else
|
||||
saved_pixel.push_back(c);
|
||||
|
||||
++saved_pixel_n;
|
||||
}
|
||||
}
|
||||
|
||||
static void drawpixel(ui::Graphics* graphics, const gfx::Point& pt, gfx::Color color)
|
||||
{
|
||||
if (saved_pixel_n < (int)saved_pixel.size() && clipping_region.contains(pt)) {
|
||||
if (cursor_negative) {
|
||||
int c = saved_pixel[saved_pixel_n++];
|
||||
int r = gfx::getr(c);
|
||||
int g = gfx::getg(c);
|
||||
int b = gfx::getb(c);
|
||||
|
||||
graphics->putPixel(color_utils::blackandwhite_neg(gfx::rgba(r, g, b)), pt.x, pt.y);
|
||||
}
|
||||
else {
|
||||
graphics->putPixel(color, pt.x, pt.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void clearpixel(ui::Graphics* g, const gfx::Point& pt, gfx::Color color)
|
||||
{
|
||||
if (saved_pixel_n < (int)saved_pixel.size()) {
|
||||
if (clipping_region.contains(pt))
|
||||
g->putPixel(saved_pixel[saved_pixel_n++], pt.x, pt.y);
|
||||
else if (!old_clipping_region.isEmpty() &&
|
||||
old_clipping_region.contains(pt))
|
||||
saved_pixel_n++;
|
||||
}
|
||||
}
|
||||
|
||||
static color_t get_brush_color(Sprite* sprite, Layer* layer)
|
||||
{
|
||||
app::Color c = Preferences::instance().colorBar.fgColor();
|
||||
ASSERT(sprite != NULL);
|
||||
|
||||
// Avoid using invalid colors
|
||||
if (!c.isValid())
|
||||
return 0;
|
||||
|
||||
if (layer != NULL)
|
||||
return color_utils::color_for_layer(c, layer);
|
||||
else
|
||||
return color_utils::color_for_image(c, sprite->pixelFormat());
|
||||
}
|
||||
|
||||
} // namespace app
|
@ -20,7 +20,6 @@
|
||||
#include "app/tools/tool_loop.h"
|
||||
#include "app/tools/tool_loop_manager.h"
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/editor/scoped_cursor.h"
|
||||
#include "app/ui/keyboard_shortcuts.h"
|
||||
#include "app/ui_context.h"
|
||||
#include "ui/message.h"
|
||||
@ -65,7 +64,9 @@ DrawingState::~DrawingState()
|
||||
|
||||
void DrawingState::initToolLoop(Editor* editor, MouseMessage* msg)
|
||||
{
|
||||
HideShowDrawingCursor hideShow(editor);
|
||||
// It's needed to clear and redraw the brush boundaries after the
|
||||
// first mouse pressed/point shape if drawn.
|
||||
HideBrushPreview hide(editor->brushPreview());
|
||||
|
||||
m_toolLoopManager->prepareLoop(pointer_from_msg(msg));
|
||||
m_toolLoopManager->pressButton(pointer_from_msg(msg));
|
||||
@ -129,16 +130,16 @@ bool DrawingState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
|
||||
m_mouseMoveReceived = true;
|
||||
|
||||
// Hide the drawing cursor
|
||||
HideShowDrawingCursor hideShow(editor);
|
||||
// It's needed to avoid some glitches with brush boundaries.
|
||||
//
|
||||
// TODO we should be able to avoid this if we correctly invalidate
|
||||
// the BrushPreview::m_clippingRegion
|
||||
HideBrushPreview hide(editor->brushPreview());
|
||||
|
||||
// Infinite scroll
|
||||
gfx::Point mousePos = editor->autoScroll(msg, AutoScroll::MouseDir, true);
|
||||
|
||||
// Hide the cursor again
|
||||
editor->hideDrawingCursor();
|
||||
|
||||
// notify mouse movement to the tool
|
||||
// Notify mouse movement to the tool
|
||||
ASSERT(m_toolLoopManager != NULL);
|
||||
m_toolLoopManager
|
||||
->movement(tools::ToolLoopManager::Pointer(mousePos.x, mousePos.y,
|
||||
@ -147,15 +148,13 @@ bool DrawingState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DrawingState::onSetCursor(Editor* editor)
|
||||
bool DrawingState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
{
|
||||
if (m_toolLoop->getInk()->isEyedropper()) {
|
||||
editor->hideDrawingCursor();
|
||||
ui::set_mouse_cursor(kEyedropperCursor);
|
||||
editor->showMouseCursor(kEyedropperCursor);
|
||||
}
|
||||
else {
|
||||
ui::set_mouse_cursor(kNoCursor);
|
||||
editor->showDrawingCursor();
|
||||
editor->showBrushPreview(mouseScreenPos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ namespace app {
|
||||
virtual bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onSetCursor(Editor* editor) override;
|
||||
virtual bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onKeyUp(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) override;
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include "app/ui/editor/moving_pixels_state.h"
|
||||
#include "app/ui/editor/pixels_movement.h"
|
||||
#include "app/ui/editor/play_state.h"
|
||||
#include "app/ui/editor/scoped_cursor.h"
|
||||
#include "app/ui/editor/standby_state.h"
|
||||
#include "app/ui/main_window.h"
|
||||
#include "app/ui/skin/skin_theme.h"
|
||||
@ -151,9 +150,7 @@ Editor::Editor(Document* document, EditorFlags flags)
|
||||
, m_layer(m_sprite->folder()->getFirstLayer())
|
||||
, m_frame(frame_t(0))
|
||||
, m_zoom(1, 1)
|
||||
, m_cursorOnScreen(false)
|
||||
, m_cursorScreen(0, 0)
|
||||
, m_cursorEditor(0, 0)
|
||||
, m_brushPreview(this)
|
||||
, m_quicktool(NULL)
|
||||
, m_selectionMode(tools::SelectionMode::DEFAULT)
|
||||
, m_offset_x(0)
|
||||
@ -219,7 +216,6 @@ Editor::~Editor()
|
||||
void Editor::destroyEditorSharedInternals()
|
||||
{
|
||||
m_renderBuffer.reset();
|
||||
exitEditorCursor();
|
||||
}
|
||||
|
||||
bool Editor::isActive() const
|
||||
@ -237,7 +233,7 @@ WidgetType editor_type()
|
||||
|
||||
void Editor::setStateInternal(const EditorStatePtr& newState)
|
||||
{
|
||||
HideShowDrawingCursor hideShow(this);
|
||||
m_brushPreview.hide();
|
||||
|
||||
// Fire before change state event, set the state, and fire after
|
||||
// change state event.
|
||||
@ -269,7 +265,7 @@ void Editor::setStateInternal(const EditorStatePtr& newState)
|
||||
m_observers.notifyStateChanged(this);
|
||||
|
||||
// Setup the new mouse cursor
|
||||
setCursor();
|
||||
setCursor(ui::get_mouse_position());
|
||||
|
||||
updateStatusBar();
|
||||
}
|
||||
@ -343,13 +339,10 @@ void Editor::setDefaultScroll()
|
||||
// Sets the scroll position of the editor
|
||||
void Editor::setEditorScroll(const gfx::Point& scroll, bool blit_valid_rgn)
|
||||
{
|
||||
HideBrushPreview hide(m_brushPreview);
|
||||
View* view = View::getView(this);
|
||||
Point oldScroll;
|
||||
Region region;
|
||||
bool onScreen = m_cursorOnScreen;
|
||||
|
||||
if (onScreen)
|
||||
clearBrushPreview();
|
||||
|
||||
if (blit_valid_rgn) {
|
||||
getDrawableRegion(region, kCutTopWindows);
|
||||
@ -363,9 +356,6 @@ void Editor::setEditorScroll(const gfx::Point& scroll, bool blit_valid_rgn)
|
||||
// Move screen with blits
|
||||
scrollRegion(region, oldScroll - newScroll);
|
||||
}
|
||||
|
||||
if (onScreen)
|
||||
drawBrushPreview(m_cursorScreen);
|
||||
}
|
||||
|
||||
void Editor::setEditorZoom(Zoom zoom)
|
||||
@ -512,6 +502,10 @@ void Editor::drawOneSpriteUnclippedRect(ui::Graphics* g, const gfx::Rect& sprite
|
||||
tmp, 0, 0, 0, 0, rc.w, rc.h);
|
||||
|
||||
g->blit(tmp, 0, 0, dest_x, dest_y, rc.w, rc.h);
|
||||
|
||||
m_brushPreview.invalidateRegion(
|
||||
gfx::Region(
|
||||
gfx::Rect(dest_x, dest_y, rc.w, rc.h)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -698,17 +692,11 @@ void Editor::drawMaskSafe()
|
||||
if (isVisible() &&
|
||||
m_document &&
|
||||
m_document->getMaskBoundaries()) {
|
||||
bool onScreen = m_cursorOnScreen;
|
||||
|
||||
Region region;
|
||||
getDrawableRegion(region, kCutTopWindows);
|
||||
region.offset(-getBounds().getOrigin());
|
||||
|
||||
if (onScreen)
|
||||
clearBrushPreview();
|
||||
else
|
||||
ui::hide_mouse_cursor();
|
||||
|
||||
HideBrushPreview hide(m_brushPreview);
|
||||
GraphicsPtr g = getGraphics(getClientBounds());
|
||||
|
||||
for (const gfx::Rect& rc : region) {
|
||||
@ -716,12 +704,6 @@ void Editor::drawMaskSafe()
|
||||
if (clip)
|
||||
drawMask(g.get());
|
||||
}
|
||||
|
||||
// Draw the cursor
|
||||
if (onScreen)
|
||||
drawBrushPreview(m_cursorScreen);
|
||||
else
|
||||
ui::show_mouse_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
@ -814,6 +796,8 @@ void Editor::flashCurrentLayer()
|
||||
|
||||
gfx::Point Editor::autoScroll(MouseMessage* msg, AutoScroll dir, bool blit_valid_rgn)
|
||||
{
|
||||
// // Hide the brush preview
|
||||
// HideBrushPreview hide(editor->brushPreview());
|
||||
View* view = View::getView(this);
|
||||
gfx::Rect vp = view->getViewportBounds();
|
||||
gfx::Point mousePos = msg->position();
|
||||
@ -857,6 +841,16 @@ gfx::Point Editor::autoScroll(MouseMessage* msg, AutoScroll dir, bool blit_valid
|
||||
return mousePos;
|
||||
}
|
||||
|
||||
void Editor::drawBrushPreview(const gfx::Point& pos)
|
||||
{
|
||||
m_brushPreview.show(pos);
|
||||
}
|
||||
|
||||
void Editor::clearBrushPreview()
|
||||
{
|
||||
m_brushPreview.hide();
|
||||
}
|
||||
|
||||
bool Editor::isCurrentToolAffectedByRightClickMode()
|
||||
{
|
||||
tools::Tool* tool = App::instance()->activeTool();
|
||||
@ -1010,43 +1004,6 @@ Rect Editor::editorToScreen(const Rect& rc)
|
||||
editorToScreen(rc.getPoint2()));
|
||||
}
|
||||
|
||||
void Editor::showDrawingCursor()
|
||||
{
|
||||
ASSERT(m_sprite != NULL);
|
||||
|
||||
if (!m_cursorOnScreen && canDraw()) {
|
||||
ui::hide_mouse_cursor();
|
||||
drawBrushPreview(ui::get_mouse_position());
|
||||
ui::show_mouse_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::hideDrawingCursor()
|
||||
{
|
||||
if (m_cursorOnScreen) {
|
||||
ui::hide_mouse_cursor();
|
||||
clearBrushPreview();
|
||||
ui::show_mouse_cursor();
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::moveDrawingCursor()
|
||||
{
|
||||
// Draw cursor
|
||||
if (m_cursorOnScreen) {
|
||||
gfx::Point mousePos = ui::get_mouse_position();
|
||||
|
||||
// Redraw it only when the mouse change to other pixel (not when
|
||||
// the mouse just moves).
|
||||
if (m_cursorScreen != mousePos) {
|
||||
ui::hide_mouse_cursor();
|
||||
clearBrushPreview();
|
||||
drawBrushPreview(mousePos);
|
||||
ui::show_mouse_cursor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::addObserver(EditorObserver* observer)
|
||||
{
|
||||
m_observers.addObserver(observer);
|
||||
@ -1081,19 +1038,16 @@ Rect Editor::getVisibleSpriteBounds()
|
||||
// Changes the scroll to see the given point as the center of the editor.
|
||||
void Editor::centerInSpritePoint(const gfx::Point& spritePos)
|
||||
{
|
||||
HideBrushPreview hide(m_brushPreview);
|
||||
View* view = View::getView(this);
|
||||
Rect vp = view->getViewportBounds();
|
||||
|
||||
hideDrawingCursor();
|
||||
|
||||
gfx::Point scroll(
|
||||
m_offset_x - (vp.w/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.x),
|
||||
m_offset_y - (vp.h/2) + m_zoom.apply(1)/2 + m_zoom.apply(spritePos.y));
|
||||
|
||||
updateEditor();
|
||||
setEditorScroll(scroll, false);
|
||||
|
||||
showDrawingCursor();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@ -1133,21 +1087,18 @@ void Editor::updateQuicktool()
|
||||
//
|
||||
// TODO We could add a quick tool observer for this
|
||||
if (old_quicktool != new_quicktool) {
|
||||
// Hide the drawing cursor with the current tool brush size before
|
||||
// we change the quicktool. In this way we avoid using the
|
||||
// quicktool brush size to clean the current tool cursor.
|
||||
// Hide the brush preview with the current tool brush size
|
||||
// before we change the quicktool. In this way we avoid using
|
||||
// the quicktool brush size to clean the current tool cursor.
|
||||
//
|
||||
// TODO Create a new Document concept of multiple extra cels: we
|
||||
// need an extra cel for the drawing cursor, other for the moving
|
||||
// pixels, etc. In this way we'll not have conflicts between
|
||||
// different uses of the same extra cel.
|
||||
if (m_state->requireBrushPreview())
|
||||
hideDrawingCursor();
|
||||
|
||||
m_quicktool = new_quicktool;
|
||||
|
||||
if (m_state->requireBrushPreview())
|
||||
showDrawingCursor();
|
||||
{
|
||||
HideBrushPreview hide(m_brushPreview);
|
||||
m_quicktool = new_quicktool;
|
||||
}
|
||||
|
||||
m_state->onQuickToolChange(this);
|
||||
|
||||
@ -1226,7 +1177,7 @@ bool Editor::onProcessMessage(Message* msg)
|
||||
break;
|
||||
|
||||
case kMouseLeaveMessage:
|
||||
hideDrawingCursor();
|
||||
m_brushPreview.hide();
|
||||
StatusBar::instance()->clearText();
|
||||
break;
|
||||
|
||||
@ -1240,7 +1191,7 @@ bool Editor::onProcessMessage(Message* msg)
|
||||
|
||||
updateQuicktool();
|
||||
updateContextBarFromModifiers();
|
||||
setCursor();
|
||||
setCursor(mouseMsg->position());
|
||||
}
|
||||
|
||||
EditorStatePtr holdState(m_state);
|
||||
@ -1258,14 +1209,15 @@ bool Editor::onProcessMessage(Message* msg)
|
||||
case kMouseUpMessage:
|
||||
if (m_sprite) {
|
||||
EditorStatePtr holdState(m_state);
|
||||
bool result = m_state->onMouseUp(this, static_cast<MouseMessage*>(msg));
|
||||
MouseMessage* mouseMsg = static_cast<MouseMessage*>(msg);
|
||||
bool result = m_state->onMouseUp(this, mouseMsg);
|
||||
|
||||
if (!hasCapture()) {
|
||||
m_secondaryButton = false;
|
||||
|
||||
updateQuicktool();
|
||||
updateContextBarFromModifiers();
|
||||
setCursor();
|
||||
setCursor(mouseMsg->position());
|
||||
}
|
||||
|
||||
if (result)
|
||||
@ -1281,7 +1233,7 @@ bool Editor::onProcessMessage(Message* msg)
|
||||
if (hasMouse()) {
|
||||
updateQuicktool();
|
||||
updateContextBarFromModifiers();
|
||||
setCursor();
|
||||
setCursor(ui::get_mouse_position());
|
||||
}
|
||||
|
||||
if (used)
|
||||
@ -1297,7 +1249,7 @@ bool Editor::onProcessMessage(Message* msg)
|
||||
if (hasMouse()) {
|
||||
updateQuicktool();
|
||||
updateContextBarFromModifiers();
|
||||
setCursor();
|
||||
setCursor(ui::get_mouse_position());
|
||||
}
|
||||
|
||||
if (used)
|
||||
@ -1320,7 +1272,7 @@ bool Editor::onProcessMessage(Message* msg)
|
||||
break;
|
||||
|
||||
case kSetCursorMessage:
|
||||
setCursor();
|
||||
setCursor(static_cast<MouseMessage*>(msg)->position());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1361,14 +1313,11 @@ void Editor::onResize(ui::ResizeEvent& ev)
|
||||
|
||||
void Editor::onPaint(ui::PaintEvent& ev)
|
||||
{
|
||||
HideBrushPreview hide(m_brushPreview);
|
||||
Graphics* g = ev.getGraphics();
|
||||
gfx::Rect rc = getClientBounds();
|
||||
SkinTheme* theme = static_cast<SkinTheme*>(this->getTheme());
|
||||
|
||||
bool onScreen = m_cursorOnScreen;
|
||||
if (onScreen)
|
||||
clearBrushPreview();
|
||||
|
||||
// Editor without sprite
|
||||
if (!m_sprite) {
|
||||
g->fillRect(theme->colors.editorFace(), rc);
|
||||
@ -1390,11 +1339,6 @@ void Editor::onPaint(ui::PaintEvent& ev)
|
||||
else {
|
||||
m_mask_timer.stop();
|
||||
}
|
||||
|
||||
// Draw the cursor again
|
||||
if (onScreen) {
|
||||
drawBrushPreview(ui::get_mouse_position());
|
||||
}
|
||||
}
|
||||
catch (const LockedDocumentException&) {
|
||||
// The sprite is locked to be read, so we can draw an opaque
|
||||
@ -1405,6 +1349,12 @@ void Editor::onPaint(ui::PaintEvent& ev)
|
||||
}
|
||||
}
|
||||
|
||||
void Editor::onInvalidateRegion(const gfx::Region& region)
|
||||
{
|
||||
Widget::onInvalidateRegion(region);
|
||||
m_brushPreview.invalidateRegion(region);
|
||||
}
|
||||
|
||||
// When the current tool is changed
|
||||
void Editor::onCurrentToolChange()
|
||||
{
|
||||
@ -1419,18 +1369,12 @@ void Editor::onCurrentToolChange()
|
||||
|
||||
void Editor::onFgColorChange()
|
||||
{
|
||||
if (m_cursorOnScreen) {
|
||||
hideDrawingCursor();
|
||||
showDrawingCursor();
|
||||
}
|
||||
m_brushPreview.redraw();
|
||||
}
|
||||
|
||||
void Editor::onBrushSizeOrAngleChange()
|
||||
{
|
||||
if (m_cursorOnScreen) {
|
||||
hideDrawingCursor();
|
||||
showDrawingCursor();
|
||||
}
|
||||
m_brushPreview.redraw();
|
||||
}
|
||||
|
||||
void Editor::onExposeSpritePixels(doc::DocumentEvent& ev)
|
||||
@ -1439,16 +1383,14 @@ void Editor::onExposeSpritePixels(doc::DocumentEvent& ev)
|
||||
m_state->onExposeSpritePixels(ev.region());
|
||||
}
|
||||
|
||||
void Editor::setCursor()
|
||||
void Editor::setCursor(const gfx::Point& mouseScreenPos)
|
||||
{
|
||||
bool used = false;
|
||||
if (m_sprite)
|
||||
used = m_state->onSetCursor(this);
|
||||
used = m_state->onSetCursor(this, mouseScreenPos);
|
||||
|
||||
if (!used) {
|
||||
hideDrawingCursor();
|
||||
ui::set_mouse_cursor(kArrowCursor);
|
||||
}
|
||||
if (!used)
|
||||
showMouseCursor(kArrowCursor);
|
||||
}
|
||||
|
||||
bool Editor::canDraw()
|
||||
@ -1474,7 +1416,7 @@ void Editor::setZoomAndCenterInMouse(Zoom zoom,
|
||||
{
|
||||
View* view = View::getView(this);
|
||||
Rect vp = view->getViewportBounds();
|
||||
HideShowDrawingCursor hideShow(this);
|
||||
HideBrushPreview hide(m_brushPreview);
|
||||
|
||||
gfx::Point screenPos;
|
||||
gfx::Point spritePos;
|
||||
@ -1547,7 +1489,7 @@ void Editor::pasteImage(const Image* image, const gfx::Point& pos)
|
||||
|
||||
// Clear brush preview, as the extra cel will be replaced with the
|
||||
// pasted image.
|
||||
hideDrawingCursor();
|
||||
m_brushPreview.hide();
|
||||
|
||||
PixelsMovementPtr pixelsMovement(
|
||||
new PixelsMovement(UIContext::instance(),
|
||||
@ -1637,6 +1579,18 @@ void Editor::setAnimationSpeedMultiplier(double speed)
|
||||
m_aniSpeed = speed;
|
||||
}
|
||||
|
||||
void Editor::showMouseCursor(CursorType cursorType)
|
||||
{
|
||||
m_brushPreview.hide();
|
||||
ui::set_mouse_cursor(cursorType);
|
||||
}
|
||||
|
||||
void Editor::showBrushPreview(const gfx::Point& screenPos)
|
||||
{
|
||||
ui::set_mouse_cursor(kNoCursor);
|
||||
m_brushPreview.show(screenPos);
|
||||
}
|
||||
|
||||
// static
|
||||
ImageBufferPtr Editor::getRenderImageBuffer()
|
||||
{
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "app/color.h"
|
||||
#include "app/document.h"
|
||||
#include "app/tools/selection_mode.h"
|
||||
#include "app/ui/editor/brush_preview.h"
|
||||
#include "app/ui/editor/editor_observers.h"
|
||||
#include "app/ui/editor/editor_state.h"
|
||||
#include "app/ui/editor/editor_states_history.h"
|
||||
@ -24,6 +25,7 @@
|
||||
#include "gfx/fwd.h"
|
||||
#include "render/zoom.h"
|
||||
#include "ui/base.h"
|
||||
#include "ui/cursor_type.h"
|
||||
#include "ui/timer.h"
|
||||
#include "ui/widget.h"
|
||||
|
||||
@ -59,8 +61,6 @@ namespace app {
|
||||
class Editor : public ui::Widget,
|
||||
public doc::DocumentObserver {
|
||||
public:
|
||||
typedef void (*PixelDelegate)(ui::Graphics*, const gfx::Point&, gfx::Color);
|
||||
|
||||
enum EditorFlags {
|
||||
kNoneFlag = 0,
|
||||
kShowGrid = 1,
|
||||
@ -118,7 +118,6 @@ namespace app {
|
||||
const render::Zoom& zoom() const { return m_zoom; }
|
||||
int offsetX() const { return m_offset_x; }
|
||||
int offsetY() const { return m_offset_y; }
|
||||
bool cursorOnScreen() const { return m_cursorOnScreen; }
|
||||
|
||||
void setZoom(render::Zoom zoom) { m_zoom = zoom; }
|
||||
void setOffsetX(int x) { m_offset_x = x; }
|
||||
@ -142,10 +141,6 @@ namespace app {
|
||||
gfx::Rect screenToEditor(const gfx::Rect& rc);
|
||||
gfx::Rect editorToScreen(const gfx::Rect& rc);
|
||||
|
||||
void showDrawingCursor();
|
||||
void hideDrawingCursor();
|
||||
void moveDrawingCursor();
|
||||
|
||||
void addObserver(EditorObserver* observer);
|
||||
void removeObserver(EditorObserver* observer);
|
||||
|
||||
@ -201,34 +196,36 @@ namespace app {
|
||||
double getAnimationSpeedMultiplier() const;
|
||||
void setAnimationSpeedMultiplier(double speed);
|
||||
|
||||
// Functions to be used in EditorState::onSetCursor()
|
||||
void showMouseCursor(ui::CursorType cursorType);
|
||||
void showBrushPreview(const gfx::Point& pos);
|
||||
|
||||
// Gets the brush preview controller.
|
||||
BrushPreview& brushPreview() { return m_brushPreview; }
|
||||
|
||||
// Returns the buffer used to render editor viewports.
|
||||
// E.g. It can be re-used by PreviewCommand
|
||||
static ImageBufferPtr getRenderImageBuffer();
|
||||
|
||||
static AppRender& renderEngine() { return m_renderEngine; }
|
||||
|
||||
// in cursor.cpp
|
||||
|
||||
static void initEditorCursor();
|
||||
|
||||
protected:
|
||||
bool onProcessMessage(ui::Message* msg) override;
|
||||
void onPreferredSize(ui::PreferredSizeEvent& ev) override;
|
||||
void onResize(ui::ResizeEvent& ev) override;
|
||||
void onPaint(ui::PaintEvent& ev) override;
|
||||
void onInvalidateRegion(const gfx::Region& region) override;
|
||||
void onCurrentToolChange();
|
||||
void onFgColorChange();
|
||||
void onBrushSizeOrAngleChange();
|
||||
void onExposeSpritePixels(doc::DocumentEvent& ev);
|
||||
|
||||
private:
|
||||
static void exitEditorCursor();
|
||||
void setStateInternal(const EditorStatePtr& newState);
|
||||
void updateQuicktool();
|
||||
void updateContextBarFromModifiers();
|
||||
void drawBrushPreview(const gfx::Point& pos);
|
||||
void clearBrushPreview();
|
||||
bool doesBrushPreviewNeedSubpixel();
|
||||
bool isCurrentToolAffectedByRightClickMode();
|
||||
|
||||
void drawMaskSafe();
|
||||
@ -236,14 +233,7 @@ namespace app {
|
||||
void drawGrid(ui::Graphics* g, const gfx::Rect& spriteBounds, const gfx::Rect& gridBounds,
|
||||
const app::Color& color, int alpha);
|
||||
|
||||
void setCursor();
|
||||
|
||||
void forEachBrushPixel(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& screenPos,
|
||||
const gfx::Point& spritePos,
|
||||
gfx::Color color,
|
||||
PixelDelegate pixelDelegate);
|
||||
void setCursor(const gfx::Point& mouseScreenPos);
|
||||
|
||||
// Draws the specified portion of sprite in the editor. Warning:
|
||||
// You should setup the clip of the screen before calling this
|
||||
@ -266,10 +256,8 @@ namespace app {
|
||||
frame_t m_frame; // Active frame in the editor
|
||||
render::Zoom m_zoom; // Zoom in the editor
|
||||
|
||||
// Drawing cursor
|
||||
bool m_cursorOnScreen;
|
||||
gfx::Point m_cursorScreen; // Position in the screen (view)
|
||||
gfx::Point m_cursorEditor; // Position in the editor (model)
|
||||
// Brush preview
|
||||
BrushPreview m_brushPreview;
|
||||
|
||||
// Current selected quicktool (this genererally should be NULL if
|
||||
// the user is not pressing any keyboard key).
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "base/disable_copying.h"
|
||||
#include "base/shared_ptr.h"
|
||||
#include "gfx/point.h"
|
||||
|
||||
namespace gfx {
|
||||
class Region;
|
||||
@ -87,7 +88,7 @@ namespace app {
|
||||
// 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; }
|
||||
virtual bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) { return false; }
|
||||
|
||||
// Called when a key is pressed over the current editor.
|
||||
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) { return false; }
|
||||
|
@ -319,20 +319,19 @@ bool MovingPixelsState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
return StandbyState::onMouseMove(editor, msg);
|
||||
}
|
||||
|
||||
bool MovingPixelsState::onSetCursor(Editor* editor)
|
||||
bool MovingPixelsState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
{
|
||||
ASSERT(m_pixelsMovement);
|
||||
ASSERT(editor == m_editor);
|
||||
|
||||
// Move selection
|
||||
if (m_pixelsMovement->isDragging()) {
|
||||
editor->hideDrawingCursor();
|
||||
ui::set_mouse_cursor(kMoveCursor);
|
||||
editor->showMouseCursor(kMoveCursor);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use StandbyState implementation
|
||||
return StandbyState::onSetCursor(editor);
|
||||
return StandbyState::onSetCursor(editor, mouseScreenPos);
|
||||
}
|
||||
|
||||
bool MovingPixelsState::onKeyDown(Editor* editor, KeyMessage* msg)
|
||||
|
@ -41,7 +41,7 @@ namespace app {
|
||||
virtual bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onSetCursor(Editor* editor) override;
|
||||
virtual bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onKeyUp(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) override;
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "app/ui/editor/editor.h"
|
||||
#include "app/ui/editor/scrolling_state.h"
|
||||
#include "ui/message.h"
|
||||
|
||||
namespace app {
|
||||
|
||||
@ -46,7 +47,7 @@ bool NavigateState::onMouseUp(Editor* editor, MouseMessage* msg)
|
||||
|
||||
bool NavigateState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
{
|
||||
editor->moveDrawingCursor();
|
||||
editor->showBrushPreview(msg->position());
|
||||
editor->updateStatusBar();
|
||||
return true;
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ bool PlayState::onMouseUp(Editor* editor, MouseMessage* msg)
|
||||
|
||||
bool PlayState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
{
|
||||
editor->moveDrawingCursor();
|
||||
editor->showBrushPreview(msg->position());
|
||||
editor->updateStatusBar();
|
||||
return true;
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2001-2015 David Capello
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License version 2 as
|
||||
// published by the Free Software Foundation.
|
||||
|
||||
#ifndef APP_UI_EDITOR_SCOPED_CURSOR_H_INCLUDED
|
||||
#define APP_UI_EDITOR_SCOPED_CURSOR_H_INCLUDED
|
||||
#pragma once
|
||||
|
||||
namespace app {
|
||||
|
||||
class HideShowDrawingCursor {
|
||||
public:
|
||||
HideShowDrawingCursor(Editor* editor)
|
||||
: m_editor(editor)
|
||||
, m_cursorOnScreen(m_editor->cursorOnScreen())
|
||||
{
|
||||
if (m_cursorOnScreen)
|
||||
m_editor->hideDrawingCursor();
|
||||
}
|
||||
~HideShowDrawingCursor() {
|
||||
if (m_cursorOnScreen)
|
||||
m_editor->showDrawingCursor();
|
||||
}
|
||||
private:
|
||||
Editor* m_editor;
|
||||
bool m_cursorOnScreen;
|
||||
};
|
||||
|
||||
} // namespace app
|
||||
|
||||
#endif
|
@ -67,10 +67,9 @@ bool ScrollingState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScrollingState::onSetCursor(Editor* editor)
|
||||
bool ScrollingState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
{
|
||||
editor->hideDrawingCursor();
|
||||
ui::set_mouse_cursor(kScrollCursor);
|
||||
editor->showMouseCursor(kScrollCursor);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace app {
|
||||
virtual bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onSetCursor(Editor* editor) override;
|
||||
virtual bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onKeyUp(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) override;
|
||||
|
@ -165,27 +165,30 @@ bool SelectBoxState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
return StandbyState::onMouseMove(editor, msg);
|
||||
}
|
||||
|
||||
bool SelectBoxState::onSetCursor(Editor* editor)
|
||||
bool SelectBoxState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
{
|
||||
if (hasFlag(RULERS)) {
|
||||
if (m_movingRuler >= 0) {
|
||||
switch (m_rulers[m_movingRuler].getOrientation()) {
|
||||
case Ruler::Horizontal: ui::set_mouse_cursor(kSizeNSCursor); return true;
|
||||
case Ruler::Vertical: ui::set_mouse_cursor(kSizeWECursor); return true;
|
||||
|
||||
case Ruler::Horizontal:
|
||||
editor->showMouseCursor(kSizeNSCursor);
|
||||
return true;
|
||||
|
||||
case Ruler::Vertical:
|
||||
editor->showMouseCursor(kSizeWECursor);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int x = ui::get_mouse_position().x;
|
||||
int y = ui::get_mouse_position().y;
|
||||
|
||||
for (Rulers::iterator it = m_rulers.begin(), end = m_rulers.end(); it != end; ++it) {
|
||||
if (touchRuler(editor, *it, x, y)) {
|
||||
if (touchRuler(editor, *it, mouseScreenPos.x, mouseScreenPos.y)) {
|
||||
switch (it->getOrientation()) {
|
||||
case Ruler::Horizontal:
|
||||
ui::set_mouse_cursor(kSizeNSCursor);
|
||||
editor->showMouseCursor(kSizeNSCursor);
|
||||
return true;
|
||||
case Ruler::Vertical:
|
||||
ui::set_mouse_cursor(kSizeWECursor);
|
||||
editor->showMouseCursor(kSizeWECursor);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -193,11 +196,11 @@ bool SelectBoxState::onSetCursor(Editor* editor)
|
||||
}
|
||||
|
||||
if (!requireBrushPreview()) {
|
||||
ui::set_mouse_cursor(kArrowCursor);
|
||||
editor->showMouseCursor(kArrowCursor);
|
||||
return true;
|
||||
}
|
||||
|
||||
return StandbyState::onSetCursor(editor);
|
||||
return StandbyState::onSetCursor(editor, mouseScreenPos);
|
||||
}
|
||||
|
||||
bool SelectBoxState::acceptQuickTool(tools::Tool* tool)
|
||||
|
@ -62,7 +62,7 @@ namespace app {
|
||||
virtual bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onSetCursor(Editor* editor) override;
|
||||
virtual bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||
virtual bool acceptQuickTool(tools::Tool* tool) override;
|
||||
virtual bool requireBrushPreview() override;
|
||||
virtual tools::Ink* getStateInk() override;
|
||||
|
@ -281,71 +281,62 @@ bool StandbyState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
callEyedropper(editor);
|
||||
}
|
||||
|
||||
editor->moveDrawingCursor();
|
||||
editor->showBrushPreview(msg->position());
|
||||
editor->updateStatusBar();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StandbyState::onSetCursor(Editor* editor)
|
||||
bool StandbyState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
{
|
||||
tools::Ink* ink = editor->getCurrentEditorInk();
|
||||
if (ink) {
|
||||
// If the current tool change selection (e.g. rectangular marquee, etc.)
|
||||
if (ink->isSelection()) {
|
||||
// See if the cursor is in some selection handle.
|
||||
if (m_decorator->onSetCursor(editor))
|
||||
if (m_decorator->onSetCursor(editor, mouseScreenPos))
|
||||
return true;
|
||||
|
||||
// Move pixels
|
||||
if (editor->isInsideSelection()) {
|
||||
EditorCustomizationDelegate* customization = editor->getCustomizationDelegate();
|
||||
|
||||
editor->hideDrawingCursor();
|
||||
|
||||
if (customization && customization->isCopySelectionKeyPressed())
|
||||
ui::set_mouse_cursor(kArrowPlusCursor);
|
||||
editor->showMouseCursor(kArrowPlusCursor);
|
||||
else
|
||||
ui::set_mouse_cursor(kMoveCursor);
|
||||
editor->showMouseCursor(kMoveCursor);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (ink->isEyedropper()) {
|
||||
editor->hideDrawingCursor();
|
||||
ui::set_mouse_cursor(kEyedropperCursor);
|
||||
editor->showMouseCursor(kEyedropperCursor);
|
||||
return true;
|
||||
}
|
||||
else if (ink->isZoom()) {
|
||||
editor->hideDrawingCursor();
|
||||
ui::set_mouse_cursor(kMagnifierCursor);
|
||||
editor->showMouseCursor(kMagnifierCursor);
|
||||
return true;
|
||||
}
|
||||
else if (ink->isScrollMovement()) {
|
||||
editor->hideDrawingCursor();
|
||||
ui::set_mouse_cursor(kScrollCursor);
|
||||
editor->showMouseCursor(kScrollCursor);
|
||||
return true;
|
||||
}
|
||||
else if (ink->isCelMovement()) {
|
||||
editor->hideDrawingCursor();
|
||||
ui::set_mouse_cursor(kMoveCursor);
|
||||
editor->showMouseCursor(kMoveCursor);
|
||||
return true;
|
||||
}
|
||||
else if (ink->isSlice()) {
|
||||
ui::set_mouse_cursor(kNoCursor);
|
||||
editor->showDrawingCursor();
|
||||
editor->showBrushPreview(mouseScreenPos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw
|
||||
if (editor->canDraw()) {
|
||||
ui::set_mouse_cursor(kNoCursor);
|
||||
editor->showDrawingCursor();
|
||||
editor->showBrushPreview(mouseScreenPos);
|
||||
}
|
||||
// Forbidden
|
||||
else {
|
||||
editor->hideDrawingCursor();
|
||||
ui::set_mouse_cursor(kForbiddenCursor);
|
||||
editor->showMouseCursor(kForbiddenCursor);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -420,7 +411,7 @@ void StandbyState::transformSelection(Editor* editor, MouseMessage* msg, HandleT
|
||||
try {
|
||||
// Clear brush preview, as the extra cel will be replaced with the
|
||||
// transformed image.
|
||||
editor->hideDrawingCursor();
|
||||
editor->brushPreview().hide();
|
||||
|
||||
EditorCustomizationDelegate* customization = editor->getCustomizationDelegate();
|
||||
Document* document = editor->document();
|
||||
@ -446,11 +437,11 @@ void StandbyState::transformSelection(Editor* editor, MouseMessage* msg, HandleT
|
||||
|
||||
// TODO steal the PixelsMovement of the other editor and use it for this one.
|
||||
StatusBar::instance()->showTip(1000, "The sprite is locked in other editor");
|
||||
ui::set_mouse_cursor(kForbiddenCursor);
|
||||
editor->showMouseCursor(kForbiddenCursor);
|
||||
}
|
||||
catch (const std::bad_alloc&) {
|
||||
StatusBar::instance()->showTip(1000, "Not enough memory to transform the selection");
|
||||
ui::set_mouse_cursor(kForbiddenCursor);
|
||||
editor->showMouseCursor(kForbiddenCursor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -492,7 +483,7 @@ TransformHandles* StandbyState::Decorator::getTransformHandles(Editor* editor)
|
||||
return m_transfHandles;
|
||||
}
|
||||
|
||||
bool StandbyState::Decorator::onSetCursor(Editor* editor)
|
||||
bool StandbyState::Decorator::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
{
|
||||
if (!editor->isActive() ||
|
||||
!editor->document()->isMaskVisible())
|
||||
@ -500,8 +491,8 @@ bool StandbyState::Decorator::onSetCursor(Editor* editor)
|
||||
|
||||
const gfx::Transformation transformation(m_standbyState->getTransformation(editor));
|
||||
TransformHandles* tr = getTransformHandles(editor);
|
||||
HandleType handle = tr->getHandleAtPoint(editor,
|
||||
ui::get_mouse_position(), transformation);
|
||||
HandleType handle = tr->getHandleAtPoint(
|
||||
editor, mouseScreenPos, transformation);
|
||||
|
||||
CursorType newCursor = kArrowCursor;
|
||||
|
||||
@ -553,9 +544,7 @@ bool StandbyState::Decorator::onSetCursor(Editor* editor)
|
||||
newCursor = rotated_rotate_cursors[(c+angle) % num];
|
||||
}
|
||||
|
||||
// Hide the drawing cursor (just in case) and show the new system cursor.
|
||||
editor->hideDrawingCursor();
|
||||
ui::set_mouse_cursor(newCursor);
|
||||
editor->showMouseCursor(newCursor);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,7 @@ namespace app {
|
||||
virtual bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onSetCursor(Editor* editor) override;
|
||||
virtual bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onKeyUp(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) override;
|
||||
@ -54,7 +54,7 @@ namespace app {
|
||||
|
||||
TransformHandles* getTransformHandles(Editor* editor);
|
||||
|
||||
bool onSetCursor(Editor* editor);
|
||||
bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos);
|
||||
|
||||
// EditorDecorator overrides
|
||||
void preRenderDecorator(EditorPreRender* render) override;
|
||||
|
@ -152,10 +152,7 @@ bool StateWithWheelBehavior::onMouseWheel(Editor* editor, MouseMessage* msg)
|
||||
}
|
||||
|
||||
gfx::Point scroll = view->getViewScroll();
|
||||
|
||||
editor->hideDrawingCursor();
|
||||
editor->setEditorScroll(scroll+delta, true);
|
||||
editor->showDrawingCursor();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -190,9 +190,7 @@ public:
|
||||
}
|
||||
|
||||
void updateDirtyArea() override {
|
||||
m_editor->hideDrawingCursor();
|
||||
m_document->notifySpritePixelsModified(m_sprite, m_dirtyArea);
|
||||
m_editor->showDrawingCursor();
|
||||
}
|
||||
|
||||
void updateStatusBar(const char* text) override {
|
||||
|
@ -78,10 +78,9 @@ bool ZoomingState::onMouseMove(Editor* editor, MouseMessage* msg)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZoomingState::onSetCursor(Editor* editor)
|
||||
bool ZoomingState::onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos)
|
||||
{
|
||||
editor->hideDrawingCursor();
|
||||
ui::set_mouse_cursor(kMagnifierCursor);
|
||||
editor->showMouseCursor(kMagnifierCursor);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ namespace app {
|
||||
virtual bool onMouseDown(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseUp(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onMouseMove(Editor* editor, ui::MouseMessage* msg) override;
|
||||
virtual bool onSetCursor(Editor* editor) override;
|
||||
virtual bool onSetCursor(Editor* editor, const gfx::Point& mouseScreenPos) override;
|
||||
virtual bool onKeyDown(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onKeyUp(Editor* editor, ui::KeyMessage* msg) override;
|
||||
virtual bool onUpdateStatusBar(Editor* editor) override;
|
||||
|
Loading…
x
Reference in New Issue
Block a user