Fix issue #237: fix pen size for square shape

+ Add Pen::getBounds().
+ Add options to increment/decrement angle with ChangePen command.
+ Add App:PenAngleBefore/AfterChange signals.
This commit is contained in:
David Capello 2013-05-22 23:58:32 -03:00
parent e90f86727b
commit 9259dd49d1
10 changed files with 142 additions and 84 deletions

View File

@ -66,6 +66,8 @@ public:
Signal0<void> PaletteChange;
Signal0<void> PenSizeBeforeChange;
Signal0<void> PenSizeAfterChange;
Signal0<void> PenAngleBeforeChange;
Signal0<void> PenAngleAfterChange;
Signal0<void> CurrentToolChange;
private:

View File

@ -33,6 +33,8 @@ class ChangePenCommand : public Command
None,
IncrementSize,
DecrementSize,
IncrementAngle,
DecrementAngle,
};
Change m_change;
@ -58,6 +60,8 @@ void ChangePenCommand::onLoadParams(Params* params)
std::string change = params->get("change");
if (change == "increment-size") m_change = IncrementSize;
else if (change == "decrement-size") m_change = DecrementSize;
else if (change == "increment-angle") m_change = IncrementAngle;
else if (change == "decrement-angle") m_change = DecrementAngle;
}
void ChangePenCommand::onExecute(Context* context)
@ -78,6 +82,14 @@ void ChangePenCommand::onExecute(Context* context)
if (pen->getSize() > 1)
pen->setSize(pen->getSize()-1);
break;
case IncrementAngle:
if (pen->getAngle() < 180)
pen->setAngle(pen->getAngle()+1);
break;
case DecrementAngle:
if (pen->getAngle() > 0)
pen->setAngle(pen->getAngle()-1);
break;
}
}

View File

@ -97,17 +97,18 @@ void image_putpixel(Image* image, int x, int y, int color)
void image_putpen(Image* image, Pen* pen, int x, int y, int fg_color, int bg_color)
{
Image* pen_image = pen->get_image();
int u, v, size = pen->get_size();
const gfx::Rect& penBounds = pen->getBounds();
x -= size/2;
y -= size/2;
x += penBounds.x;
y += penBounds.y;
if (fg_color == bg_color) {
image_rectfill(image, x, y, x+pen_image->w-1, y+pen_image->h-1, bg_color);
image_rectfill(image, x, y, x+penBounds.w-1, y+penBounds.h-1, bg_color);
}
else {
for (v=0; v<pen_image->h; v++) {
for (u=0; u<pen_image->w; u++) {
int u, v;
for (v=0; v<penBounds.h; v++) {
for (u=0; u<penBounds.w; u++) {
if (image_getpixel(pen_image, u, v))
image_putpixel(image, x+u, y+v, fg_color);
else

View File

@ -95,63 +95,75 @@ static void algo_hline(int x1, int y, int x2, void *data)
// Regenerates the pen bitmap and its rectangle's region.
void Pen::regenerate_pen()
{
int x, y;
clean_pen();
m_image = Image::create(IMAGE_BITMAP, m_size, m_size);
image_clear(m_image, 0);
ASSERT(m_size > 0);
switch (m_type) {
int size = m_size;
if (m_type == PEN_TYPE_SQUARE && m_angle != 0 && m_size > 2)
size = std::sqrt(2*m_size*m_size)+2;
case PEN_TYPE_CIRCLE:
image_ellipsefill(m_image, 0, 0, m_size-1, m_size-1, 1);
break;
m_image = Image::create(IMAGE_BITMAP, size, size);
case PEN_TYPE_SQUARE: {
double a = PI * m_angle / 180;
int r = m_size/2;
int x1, y1, x2, y2, x3, y3, x4, y4;
if (size == 1) {
image_clear(m_image, 1);
}
else {
image_clear(m_image, 0);
x1 = cos(a+ PI/4) * r;
y1 = -sin(a+ PI/4) * r;
x2 = cos(a+3*PI/4) * r;
y2 = -sin(a+3*PI/4) * r;
x3 = cos(a-3*PI/4) * r;
y3 = -sin(a-3*PI/4) * r;
x4 = cos(a- PI/4) * r;
y4 = -sin(a- PI/4) * r;
switch (m_type) {
image_line(m_image, r+x1, r+y1, r+x2, r+y2, 1);
image_line(m_image, r+x2, r+y2, r+x3, r+y3, 1);
image_line(m_image, r+x3, r+y3, r+x4, r+y4, 1);
image_line(m_image, r+x4, r+y4, r+x1, r+y1, 1);
case PEN_TYPE_CIRCLE:
image_ellipsefill(m_image, 0, 0, size-1, size-1, 1);
break;
algo_floodfill(m_image, r, r, 0, m_image, algo_hline);
break;
}
case PEN_TYPE_SQUARE:
if (m_angle == 0 || size <= 2) {
image_clear(m_image, 1);
}
else {
double a = PI * m_angle / 180;
int c = size/2;
int r = m_size/2;
int d = m_size;
int x1 = c + r*cos(a-PI/2) + r*cos(a-PI);
int y1 = c - r*sin(a-PI/2) - r*sin(a-PI);
int x2 = x1 + d*cos(a);
int y2 = y1 - d*sin(a);
int x3 = x2 + d*cos(a+PI/2);
int y3 = y2 - d*sin(a+PI/2);
int x4 = x3 + d*cos(a+PI);
int y4 = y3 - d*sin(a+PI);
int points[8] = { x1, y1, x2, y2, x3, y3, x4, y4 };
case PEN_TYPE_LINE: {
double a = PI * m_angle / 180;
int r = m_size/2;
algo_polygon(4, points, m_image, algo_hline);
}
break;
x = cos(a) * r;
y = -sin(a) * r;
image_line(m_image, r-x, r-y, r+x, r+y, 1);
image_line(m_image, r-x-1, r-y, r+x-1, r+y, 1);
break;
case PEN_TYPE_LINE: {
double a = PI * m_angle / 180;
float r = m_size/2;
float d = m_size;
int x1 = r + r*cos(a+PI);
int y1 = r - r*sin(a+PI);
int x2 = x1 + d*cos(a);
int y2 = y1 - d*sin(a);
image_line(m_image, x1, y1, x2, y2, 1);
break;
}
}
}
m_scanline.resize(m_size);
for (y=0; y<m_size; y++) {
m_scanline.resize(m_image->h);
for (int y=0; y<m_image->h; y++) {
m_scanline[y].state = false;
for (x=0; x<m_size; x++) {
for (int x=0; x<m_image->w; x++) {
if (image_getpixel(m_image, x, y)) {
m_scanline[y].x1 = x;
for (; x<m_size; x++)
for (; x<m_image->w; x++)
if (!image_getpixel(m_image, x, y))
break;
@ -161,4 +173,7 @@ void Pen::regenerate_pen()
}
}
}
m_bounds = gfx::Rect(-m_image->w/2, -m_image->h/2,
m_image->w, m_image->h);
}

View File

@ -19,6 +19,8 @@
#ifndef RASTER_PEN_H_INCLUDED
#define RASTER_PEN_H_INCLUDED
#include "gfx/point.h"
#include "gfx/rect.h"
#include "raster/pen_type.h"
#include <vector>
@ -43,6 +45,8 @@ public:
Image* get_image() { return m_image; }
const std::vector<PenScanline>& get_scanline() const { return m_scanline; }
const gfx::Rect& getBounds() const { return m_bounds; }
void set_type(PenType type);
void set_size(int size);
void set_angle(int angle);
@ -51,11 +55,12 @@ private:
void clean_pen();
void regenerate_pen();
PenType m_type; /* type of pen */
int m_size; /* size (diameter) */
int m_angle; /* angle in degrees 0-360 */
Image* m_image; /* image of the pen */
PenType m_type; // Type of pen
int m_size; // Size (diameter)
int m_angle; // Angle in degrees 0-360
Image* m_image; // Image of the pen
std::vector<PenScanline> m_scanline;
gfx::Rect m_bounds;
};
#endif

View File

@ -209,14 +209,16 @@ void UISettingsImpl::setBgColor(const app::Color& color)
void UISettingsImpl::setCurrentTool(tools::Tool* tool)
{
if (m_currentTool != tool) {
// Fire PenSizeBeforeChange signal (maybe the new selected tool has a different pen size)
// Fire signals (maybe the new selected tool has a different pen size)
App::instance()->PenSizeBeforeChange();
App::instance()->PenAngleBeforeChange();
// Change the tool
m_currentTool = tool;
App::instance()->CurrentToolChange(); // Fire CurrentToolChange signal
App::instance()->PenSizeAfterChange(); // Fire PenSizeAfterChange signal
App::instance()->PenAngleAfterChange(); // Fire PenAngleAfterChange signal
}
}
@ -446,7 +448,15 @@ public:
void setAngle(int angle)
{
// Trigger PenAngleBeforeChange signal
if (m_fireSignals)
App::instance()->PenAngleBeforeChange();
m_angle = MID(0, angle, 360);
// Trigger PenAngleAfterChange signal
if (m_fireSignals)
App::instance()->PenAngleAfterChange();
}
void enableSignals(bool state)

View File

@ -49,23 +49,23 @@ public:
{
Pen* pen = loop->getPen();
std::vector<PenScanline>::const_iterator scanline = pen->get_scanline().begin();
register int h = pen->get_size();
register int c = h/2;
register int v, h = pen->getBounds().h;
x -= c;
y -= c;
x += pen->getBounds().x;
y += pen->getBounds().y;
for (c=0; c<h; c++) {
for (v=0; v<h; ++v) {
if (scanline->state)
doInkHline(x+scanline->x1, y+c, x+scanline->x2, loop);
doInkHline(x+scanline->x1, y+v, x+scanline->x2, loop);
++scanline;
}
}
void getModifiedArea(ToolLoop* loop, int x, int y, Rect& area)
{
Pen* pen = loop->getPen();
int size = pen->get_size();
area = Rect(x-size/2, y-size/2, size, size);
area = pen->getBounds();
area.x += x;
area.y += y;
}
};

View File

@ -363,7 +363,8 @@ ContextBar::ContextBar()
tooltipManager->addTooltipFor(m_sprayWidth, "Spray Width", JI_CENTER | JI_BOTTOM);
tooltipManager->addTooltipFor(m_spraySpeed, "Spray Speed", JI_CENTER | JI_BOTTOM);
App::instance()->PenSizeAfterChange.connect(&ContextBar::onPenSizeAfterChange, this);
App::instance()->PenSizeAfterChange.connect(&ContextBar::onPenSizeChange, this);
App::instance()->PenAngleAfterChange.connect(&ContextBar::onPenAngleChange, this);
App::instance()->CurrentToolChange.connect(&ContextBar::onCurrentToolChange, this);
onCurrentToolChange();
@ -378,7 +379,7 @@ bool ContextBar::onProcessMessage(Message* msg)
return Box::onProcessMessage(msg);
}
void ContextBar::onPenSizeAfterChange()
void ContextBar::onPenSizeChange()
{
ISettings* settings = UIContext::instance()->getSettings();
Tool* currentTool = settings->getCurrentTool();
@ -389,6 +390,17 @@ void ContextBar::onPenSizeAfterChange()
m_brushSize->setTextf("%d", penSettings->getSize());
}
void ContextBar::onPenAngleChange()
{
ISettings* settings = UIContext::instance()->getSettings();
Tool* currentTool = settings->getCurrentTool();
IToolSettings* toolSettings = settings->getToolSettings(currentTool);
IPenSettings* penSettings = toolSettings->getPen();
m_brushType->setPenSettings(penSettings);
m_brushAngle->setTextf("%d", penSettings->getAngle());
}
void ContextBar::onCurrentToolChange()
{
ISettings* settings = UIContext::instance()->getSettings();

View File

@ -37,7 +37,8 @@ protected:
bool onProcessMessage(ui::Message* msg) OVERRIDE;
private:
void onPenSizeAfterChange();
void onPenSizeChange();
void onPenAngleChange();
void onCurrentToolChange();
class BrushTypeField;

View File

@ -150,7 +150,7 @@ static void on_palette_change_update_cursor_color()
update_cursor_color();
}
static void on_pen_size_before_change()
static void on_pen_before_change()
{
if (current_editor != NULL) {
pen_size_thick = current_editor->getCursorThick();
@ -159,7 +159,7 @@ static void on_pen_size_before_change()
}
}
static void on_pen_size_after_change()
static void on_pen_after_change()
{
if (current_editor != NULL) {
// Show drawing cursor
@ -205,8 +205,10 @@ void Editor::editor_cursor_init()
set_cursor_color(get_config_color("Tools", "CursorColor", app::Color::fromMask()));
App::instance()->PaletteChange.connect(&on_palette_change_update_cursor_color);
App::instance()->PenSizeBeforeChange.connect(&on_pen_size_before_change);
App::instance()->PenSizeAfterChange.connect(&on_pen_size_after_change);
App::instance()->PenSizeBeforeChange.connect(&on_pen_before_change);
App::instance()->PenSizeAfterChange.connect(&on_pen_after_change);
App::instance()->PenAngleBeforeChange.connect(&on_pen_before_change);
App::instance()->PenAngleAfterChange.connect(&on_pen_after_change);
}
void Editor::editor_cursor_exit()
@ -284,12 +286,11 @@ void Editor::editor_draw_cursor(int x, int y, bool refresh)
int pen_color = get_pen_color(m_sprite, m_layer);
uint32_t new_mask_color;
Pen* pen = editor_get_current_pen();
int half = pen->get_size()/2;
gfx::Rect penBounds = pen->getBounds();
// Create the extra cel to show the pen preview
m_document->prepareExtraCel(x-half,
y-half,
pen->get_size(), pen->get_size(),
m_document->prepareExtraCel(x+penBounds.x, y+penBounds.y,
penBounds.w, penBounds.h,
tool_settings->getOpacity());
// In 'indexed' images, if the current color is 0, we have to use
@ -304,15 +305,15 @@ void Editor::editor_draw_cursor(int x, int y, bool refresh)
Image* extraImage = m_document->getExtraCelImage();
if (extraImage->mask_color != new_mask_color)
image_clear(extraImage, extraImage->mask_color = new_mask_color);
image_putpen(extraImage, pen, half, half, pen_color, extraImage->mask_color);
image_putpen(extraImage, pen, -penBounds.x, -penBounds.y,
pen_color, extraImage->mask_color);
if (refresh) {
m_document->notifySpritePixelsModified
(m_sprite,
gfx::Region(gfx::Rect(x-half,
y-half,
pen->get_size(),
pen->get_size())));
gfx::Region(gfx::Rect(x+penBounds.x,
y+penBounds.y,
penBounds.w, penBounds.h)));
}
}
@ -362,9 +363,9 @@ void Editor::editor_move_cursor(int x, int y, bool refresh)
if (cursor_type & CURSOR_PENCIL && m_state->requirePenPreview()) {
Pen* pen = editor_get_current_pen();
int half = pen->get_size()/2;
gfx::Rect rc1(old_x-half, old_y-half, pen->get_size(), pen->get_size());
gfx::Rect rc2(new_x-half, new_y-half, pen->get_size(), pen->get_size());
gfx::Rect penBounds = pen->getBounds();
gfx::Rect rc1(old_x+penBounds.x, old_y+penBounds.y, penBounds.w, penBounds.h);
gfx::Rect rc2(new_x+penBounds.x, new_y+penBounds.y, penBounds.w, penBounds.h);
m_document->notifySpritePixelsModified
(m_sprite, gfx::Region(rc1.createUnion(rc2)));
}
@ -417,19 +418,18 @@ void Editor::editor_clean_cursor(bool refresh)
// clean pixel/pen preview
if (cursor_type & CURSOR_PENCIL && m_state->requirePenPreview()) {
Pen* pen = editor_get_current_pen();
gfx::Rect penBounds = pen->getBounds();
m_document->prepareExtraCel(x-pen->get_size()/2,
y-pen->get_size()/2,
pen->get_size(), pen->get_size(),
m_document->prepareExtraCel(x+penBounds.x, y+penBounds.y,
penBounds.w, penBounds.h,
0); // Opacity = 0
if (refresh) {
m_document->notifySpritePixelsModified
(m_sprite,
gfx::Region(gfx::Rect(x-pen->get_size()/2,
y-pen->get_size()/2,
pen->get_size(),
pen->get_size())));
gfx::Region(gfx::Rect(x+penBounds.x,
y+penBounds.y,
penBounds.w, penBounds.h)));
}
}