mirror of
https://github.com/aseprite/aseprite.git
synced 2024-10-03 21:46:20 +00:00
Merge branch 'master' into beta
This commit is contained in:
commit
49d5787737
2
laf
2
laf
@ -1 +1 @@
|
||||
Subproject commit 0b2e8b7a401aa34c245afe5e0114a498d4e341cd
|
||||
Subproject commit 6cff5d558e88c6726339fe977d2630db367f9f58
|
@ -31,6 +31,7 @@
|
||||
#include "app/ui_context.h"
|
||||
#include "app/util/wrap_value.h"
|
||||
#include "base/debug.h"
|
||||
#include "base/scoped_value.h"
|
||||
#include "doc/algo.h"
|
||||
#include "doc/blend_internals.h"
|
||||
#include "doc/brush.h"
|
||||
@ -38,7 +39,9 @@
|
||||
#include "doc/image_impl.h"
|
||||
#include "doc/layer.h"
|
||||
#include "doc/primitives.h"
|
||||
#include "gfx/rect_io.h"
|
||||
#include "os/surface.h"
|
||||
#include "os/system.h"
|
||||
#include "os/window.h"
|
||||
#include "render/render.h"
|
||||
#include "ui/manager.h"
|
||||
#include "ui/system.h"
|
||||
@ -49,17 +52,12 @@ using namespace doc;
|
||||
|
||||
BrushPreview::BrushPreview(Editor* editor)
|
||||
: m_editor(editor)
|
||||
, m_type(CROSSHAIR)
|
||||
, m_onScreen(false)
|
||||
, m_withModifiedPixels(false)
|
||||
, m_withRealPreview(false)
|
||||
, m_screenPosition(0, 0)
|
||||
, m_editorPosition(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
BrushPreview::~BrushPreview()
|
||||
{
|
||||
m_cursor.reset();
|
||||
}
|
||||
|
||||
BrushRef BrushPreview::getCurrentBrush()
|
||||
@ -352,8 +350,13 @@ void BrushPreview::show(const gfx::Point& screenPos)
|
||||
ui::ScreenGraphics g(m_editor->display());
|
||||
ui::SetClip clip(&g);
|
||||
gfx::Color uiCursorColor = color_utils::color_for_ui(appCursorColor);
|
||||
forEachBrushPixel(&g, m_screenPosition, spritePos, uiCursorColor, &BrushPreview::savePixelDelegate);
|
||||
forEachBrushPixel(&g, m_screenPosition, spritePos, uiCursorColor, &BrushPreview::drawPixelDelegate);
|
||||
|
||||
createNativeCursor();
|
||||
if (m_cursor)
|
||||
forEachLittleCrossPixel(&g, m_screenPosition, uiCursorColor, &BrushPreview::putPixelInCursorDelegate);
|
||||
|
||||
forEachBrushPixel(&g, spritePos, uiCursorColor, &BrushPreview::savePixelDelegate);
|
||||
forEachBrushPixel(&g, spritePos, uiCursorColor, &BrushPreview::drawPixelDelegate);
|
||||
m_withModifiedPixels = true;
|
||||
}
|
||||
|
||||
@ -378,6 +381,12 @@ void BrushPreview::hide()
|
||||
if (!m_onScreen)
|
||||
return;
|
||||
|
||||
// Don't hide the cursor to avoid flickering, the native mouse
|
||||
// cursor will be changed anyway after the hide() by the caller.
|
||||
//
|
||||
//if (m_cursor)
|
||||
// m_editor->m_editor->display()->nativeWindow()->setNativeMouseCursor(os::NativeCursor::Hidden);
|
||||
|
||||
// Get drawable region
|
||||
m_editor->getDrawableRegion(m_clippingRegion, ui::Widget::kCutTopWindows);
|
||||
|
||||
@ -389,7 +398,7 @@ void BrushPreview::hide()
|
||||
// Restore pixels
|
||||
ui::ScreenGraphics g(m_editor->display());
|
||||
ui::SetClip clip(&g);
|
||||
forEachBrushPixel(&g, m_screenPosition, m_editorPosition, gfx::ColorNone,
|
||||
forEachBrushPixel(&g, m_editorPosition, gfx::ColorNone,
|
||||
&BrushPreview::clearPixelDelegate);
|
||||
}
|
||||
|
||||
@ -411,6 +420,7 @@ void BrushPreview::hide()
|
||||
}
|
||||
|
||||
m_onScreen = false;
|
||||
|
||||
m_clippingRegion.clear();
|
||||
m_oldClippingRegion.clear();
|
||||
}
|
||||
@ -451,12 +461,7 @@ void BrushPreview::generateBoundaries()
|
||||
(m_editor->getCurrentEditorTool()->getPointShape(0)->isPixel() ||
|
||||
m_editor->getCurrentEditorTool()->getPointShape(0)->isFloodFill());
|
||||
Image* brushImage = brush->image();
|
||||
int w = (isOnePixel ? 1: brushImage->width());
|
||||
int h = (isOnePixel ? 1: brushImage->height());
|
||||
|
||||
m_brushGen = brush->gen();
|
||||
m_brushWidth = w;
|
||||
m_brushHeight = h;
|
||||
|
||||
Image* mask = nullptr;
|
||||
bool deleteMask = true;
|
||||
@ -479,30 +484,89 @@ void BrushPreview::generateBoundaries()
|
||||
delete mask;
|
||||
}
|
||||
|
||||
void BrushPreview::forEachBrushPixel(
|
||||
void BrushPreview::createNativeCursor()
|
||||
{
|
||||
gfx::Rect cursorBounds;
|
||||
|
||||
if (m_type & CROSSHAIR) {
|
||||
cursorBounds |= gfx::Rect(-3, -3, 7, 7);
|
||||
m_cursorCenter = -cursorBounds.origin();
|
||||
}
|
||||
// Special case of a cursor for one pixel
|
||||
else if (!(m_type & NATIVE_CROSSHAIR) &&
|
||||
m_editor->zoom().scale() >= 4.0) {
|
||||
cursorBounds = gfx::Rect(0, 0, 1, 1);
|
||||
m_cursorCenter = gfx::Point(0, 0);
|
||||
}
|
||||
|
||||
if (m_cursor) {
|
||||
if (m_cursor->width() != cursorBounds.w ||
|
||||
m_cursor->height() != cursorBounds.h) {
|
||||
m_cursor.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (cursorBounds.isEmpty()) {
|
||||
ASSERT(!m_cursor);
|
||||
m_editor->display()->nativeWindow()->setNativeMouseCursor(os::NativeCursor::Hidden);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_cursor) {
|
||||
m_cursor = os::instance()->makeRgbaSurface(cursorBounds.w, cursorBounds.h);
|
||||
|
||||
// Cannot clear the cursor on each iteration because it can
|
||||
// generate a flicker effect when zooming in the same mouse
|
||||
// position. That's strange.
|
||||
m_cursor->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void BrushPreview::forEachLittleCrossPixel(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& screenPos,
|
||||
const gfx::Point& spritePos,
|
||||
gfx::Color color,
|
||||
PixelDelegate pixelDelegate)
|
||||
{
|
||||
m_savedPixelsIterator = 0;
|
||||
|
||||
if (m_type & CROSSHAIR)
|
||||
traceCrossPixels(g, screenPos, color, pixelDelegate);
|
||||
|
||||
if (m_type & SELECTION_CROSSHAIR)
|
||||
traceSelectionCrossPixels(g, spritePos, color, 1, pixelDelegate);
|
||||
|
||||
if (m_type & BRUSH_BOUNDARIES)
|
||||
traceBrushBoundaries(g, spritePos, color, pixelDelegate);
|
||||
|
||||
// Depending on the editor zoom, maybe we need subpixel movement (a
|
||||
// little dot inside the active pixel)
|
||||
if (!(m_type & NATIVE_CROSSHAIR) &&
|
||||
m_editor->zoom().scale() >= 4.0) {
|
||||
(this->*pixelDelegate)(g, screenPos, color);
|
||||
}
|
||||
else {
|
||||
// We'll remove the pixel (as we didn't called Surface::clear() to
|
||||
// avoid a flickering issue when zooming in the same mouse
|
||||
// position).
|
||||
base::ScopedValue<bool> restore(m_blackAndWhiteNegative, false,
|
||||
m_blackAndWhiteNegative);
|
||||
(this->*pixelDelegate)(g, screenPos, gfx::ColorNone);
|
||||
}
|
||||
|
||||
if (m_cursor) {
|
||||
m_editor->display()->nativeWindow()->setNativeMouseCursor(
|
||||
m_cursor.get(),
|
||||
m_cursorCenter,
|
||||
m_editor->display()->nativeWindow()->scale());
|
||||
}
|
||||
}
|
||||
|
||||
void BrushPreview::forEachBrushPixel(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& spritePos,
|
||||
gfx::Color color,
|
||||
PixelDelegate pixelDelegate)
|
||||
{
|
||||
m_savedPixelsIterator = 0;
|
||||
|
||||
if (m_type & SELECTION_CROSSHAIR)
|
||||
traceSelectionCrossPixels(g, spritePos, color, 1, pixelDelegate);
|
||||
|
||||
if (m_type & BRUSH_BOUNDARIES)
|
||||
traceBrushBoundaries(g, spritePos, color, pixelDelegate);
|
||||
|
||||
m_savedPixelsLimit = m_savedPixelsIterator;
|
||||
}
|
||||
@ -535,9 +599,7 @@ void BrushPreview::traceCrossPixels(
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Old Thick Cross
|
||||
|
||||
// Old thick cross (used for selection tools)
|
||||
void BrushPreview::traceSelectionCrossPixels(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& pt, gfx::Color color,
|
||||
@ -574,9 +636,7 @@ void BrushPreview::traceSelectionCrossPixels(
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Current Brush Bounds
|
||||
|
||||
// Current brush edges
|
||||
void BrushPreview::traceBrushBoundaries(ui::Graphics* g,
|
||||
gfx::Point pos,
|
||||
gfx::Color color,
|
||||
@ -604,6 +664,33 @@ void BrushPreview::traceBrushBoundaries(ui::Graphics* g,
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Pixel delegates
|
||||
|
||||
void BrushPreview::putPixelInCursorDelegate(ui::Graphics* g, const gfx::Point& pt, gfx::Color color)
|
||||
{
|
||||
ASSERT(m_cursor);
|
||||
|
||||
if (!m_clippingRegion.contains(pt))
|
||||
return;
|
||||
|
||||
if (m_blackAndWhiteNegative) {
|
||||
color_t c = g->getPixel(pt.x, pt.y);
|
||||
int r = gfx::getr(c);
|
||||
int g = gfx::getg(c);
|
||||
int b = gfx::getb(c);
|
||||
|
||||
m_cursor->putPixel(color_utils::blackandwhite_neg(gfx::rgba(r, g, b)),
|
||||
pt.x - m_screenPosition.x + m_cursorCenter.x,
|
||||
pt.y - m_screenPosition.y + m_cursorCenter.y);
|
||||
}
|
||||
else {
|
||||
m_cursor->putPixel(color,
|
||||
pt.x - m_screenPosition.x + m_cursorCenter.x,
|
||||
pt.y - m_screenPosition.y + m_cursorCenter.y);
|
||||
}
|
||||
}
|
||||
|
||||
void BrushPreview::savePixelDelegate(ui::Graphics* g, const gfx::Point& pt, gfx::Color color)
|
||||
{
|
||||
if (m_clippingRegion.contains(pt)) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
// Aseprite
|
||||
// Copyright (C) 2019-2020 Igara Studio S.A.
|
||||
// Copyright (C) 2019-2021 Igara Studio S.A.
|
||||
// Copyright (C) 2001-2016 David Capello
|
||||
//
|
||||
// This program is distributed under the terms of
|
||||
@ -18,6 +18,7 @@
|
||||
#include "gfx/point.h"
|
||||
#include "gfx/rect.h"
|
||||
#include "gfx/region.h"
|
||||
#include "os/surface.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -37,10 +38,34 @@ namespace app {
|
||||
public:
|
||||
// Brush type
|
||||
enum {
|
||||
CROSSHAIR = 1,
|
||||
// A simple cursor in the mouse position for drawing tools. The
|
||||
// crosshair is painted in real-time with black and white
|
||||
// depending on the pixel of the screen.
|
||||
//
|
||||
// |
|
||||
// |
|
||||
// --- * ---
|
||||
// |
|
||||
// |
|
||||
CROSSHAIR = 1,
|
||||
|
||||
// Crosshair used in the selection tools in the sprite position.
|
||||
//
|
||||
// | |
|
||||
// -- --
|
||||
// *
|
||||
// -- --
|
||||
// | |
|
||||
SELECTION_CROSSHAIR = 2,
|
||||
BRUSH_BOUNDARIES = 4,
|
||||
NATIVE_CROSSHAIR = 8,
|
||||
|
||||
// The boundaries of the brush used in the sprite position
|
||||
// (depends on the shape of the brush generated with
|
||||
// doc::MaskBoundaries).
|
||||
BRUSH_BOUNDARIES = 4,
|
||||
|
||||
// Use a pre-defined native cursor that is a crosshair in the
|
||||
// mouse position.
|
||||
NATIVE_CROSSHAIR = 8,
|
||||
};
|
||||
|
||||
BrushPreview(Editor* editor);
|
||||
@ -63,9 +88,16 @@ namespace app {
|
||||
static doc::color_t getBrushColor(doc::Sprite* sprite, doc::Layer* layer);
|
||||
|
||||
void generateBoundaries();
|
||||
void forEachBrushPixel(
|
||||
|
||||
// Creates a little native cursor to draw the CROSSHAIR
|
||||
void createNativeCursor();
|
||||
void forEachLittleCrossPixel(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& screenPos,
|
||||
gfx::Color color,
|
||||
PixelDelegate pixelDelegate);
|
||||
void forEachBrushPixel(
|
||||
ui::Graphics* g,
|
||||
const gfx::Point& spritePos,
|
||||
gfx::Color color,
|
||||
PixelDelegate pixelDelegate);
|
||||
@ -74,30 +106,36 @@ namespace app {
|
||||
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 putPixelInCursorDelegate(ui::Graphics* g, const gfx::Point& pt, gfx::Color color);
|
||||
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;
|
||||
int m_type = CROSSHAIR;
|
||||
|
||||
// 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;
|
||||
bool m_withModifiedPixels;
|
||||
bool m_withRealPreview;
|
||||
bool m_onScreen = false;
|
||||
|
||||
bool m_withRealPreview = false;
|
||||
gfx::Point m_screenPosition; // Position in the screen (view)
|
||||
gfx::Point m_editorPosition; // Position in the editor (model)
|
||||
|
||||
// Native mouse cursor to draw crosshair
|
||||
os::SurfaceRef m_cursor;
|
||||
gfx::Point m_cursorCenter;
|
||||
|
||||
// Information about current brush
|
||||
doc::MaskBoundaries m_brushBoundaries;
|
||||
int m_brushGen;
|
||||
int m_brushWidth;
|
||||
int m_brushHeight;
|
||||
|
||||
// True if we've modified pixels in the display surface
|
||||
// (e.g. drawing the selection crosshair or the brush edges).
|
||||
bool m_withModifiedPixels = false;
|
||||
std::vector<gfx::Color> m_savedPixels;
|
||||
int m_savedPixelsIterator;
|
||||
int m_savedPixelsLimit;
|
||||
|
@ -45,6 +45,13 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_WIN32) && defined(DEBUG_PAINT_EVENTS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
namespace ui {
|
||||
|
||||
namespace {
|
||||
@ -1568,15 +1575,23 @@ bool Manager::sendMessageToWidget(Message* msg, Widget* widget)
|
||||
#ifdef DEBUG_PAINT_EVENTS
|
||||
{
|
||||
os::SurfaceLock lock(surface);
|
||||
surface->fillRect(gfx::rgba(0, 0, 255), paintMsg->rect());
|
||||
os::Paint p;
|
||||
p.color(gfx::rgba(0, 0, 255));
|
||||
surface->drawRect(paintMsg->rect(), p);
|
||||
}
|
||||
|
||||
if (m_window) {
|
||||
m_window->invalidateRegion(gfx::Region(m_window->bounds()));
|
||||
// TODO m_window->update() ??
|
||||
|
||||
#ifdef _WIN32 // TODO add a m_display->updateNow() method ??
|
||||
HWND hwnd = (HWND)m_display->nativeHandle();
|
||||
UpdateWindow(hwnd);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
base::this_thread::sleep_for(0.002);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (surface) {
|
||||
|
Loading…
Reference in New Issue
Block a user